diff options
47 files changed, 4224 insertions, 3699 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000000..7895ada36da --- /dev/null +++ b/.clang-format @@ -0,0 +1,27 @@ +Language: Cpp +BasedOnStyle: LLVM +AlignEscapedNewlinesLeft: true +AlwaysBreakAfterReturnType: TopLevelDefinitions +BreakBeforeBinaryOperators: All +BreakBeforeBraces: GNU +ColumnLimit: 80 +ContinuationIndentWidth: 2 +ForEachMacros: [FOR_EACH_TAIL, FOR_EACH_TAIL_SAFE] +IncludeCategories: + - Regex: '^<config\.h>$' + Priority: -1 + - Regex: '^<' + Priority: 1 + - Regex: '^"lisp\.h"$' + Priority: 2 + - Regex: '.*' + Priority: 3 +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +PenaltyBreakBeforeFirstCallParameter: 2000 +SpaceAfterCStyleCast: true +SpaceBeforeParens: Always + +# Local Variables: +# mode: yaml +# End: @@ -2,7 +2,7 @@ Copyright (C) 2001-2017 Free Software Foundation, Inc. See the end of the file for license conditions. -This directory tree holds version 26.0.60 of GNU Emacs, the extensible, +This directory tree holds version 27.0.50 of GNU Emacs, the extensible, customizable, self-documenting real-time display editor. The file INSTALL in this directory says how to build and install GNU diff --git a/admin/gitmerge.el b/admin/gitmerge.el index 0dfd190d753..fa8c9c0f3de 100644 --- a/admin/gitmerge.el +++ b/admin/gitmerge.el @@ -67,7 +67,7 @@ re-?generate\\|bump version\\|from trunk\\|Auto-commit" '((t (:strike-through t))) "Face for skipped commits.") -(defconst gitmerge-default-branch "origin/emacs-25" +(defconst gitmerge-default-branch "origin/emacs-26" "Default for branch that should be merged.") (defconst gitmerge-buffer "*gitmerge*" diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt index 5822f666db4..690125ad572 100644 --- a/admin/make-tarball.txt +++ b/admin/make-tarball.txt @@ -5,7 +5,7 @@ Instructions to create pretest or release tarballs. -*- coding: utf-8 -*- Steps to take before starting on the first pretest in any release sequence: -0. The release branch (e.g. emacs-25) should already have been made +0. The release branch (e.g. emacs-26) should already have been made and you should use it for all that follows. Diffs from this branch should be going to the emacs-diffs mailing list. diff --git a/admin/notes/git-workflow b/admin/notes/git-workflow index 2e4bbac70fe..cb10638af82 100644 --- a/admin/notes/git-workflow +++ b/admin/notes/git-workflow @@ -19,15 +19,15 @@ Initial setup ============= Then we want to clone the repository. We normally want to have both -the current master and the emacs-25 branch. +the current master and the emacs-26 branch. mkdir ~/emacs cd ~/emacs git clone <membername>@git.sv.gnu.org:/srv/git/emacs.git master (cd master; git config push.default current) -./master/admin/git-new-workdir master emacs-25 -cd emacs-25 -git checkout emacs-25 +./master/admin/git-new-workdir master emacs-26 +cd emacs-26 +git checkout emacs-26 You now have both branches conveniently accessible, and you can do "git pull" in them once in a while to keep updated. @@ -57,11 +57,11 @@ you commit your change locally and then send a patch file as a bug report as described in ../../CONTRIBUTE. -Backporting to emacs-25 +Backporting to emacs-26 ======================= If you have applied a fix to the master, but then decide that it should -be applied to the emacs-25 branch, too, then +be applied to the emacs-26 branch, too, then cd ~/emacs/master git log @@ -71,7 +71,7 @@ which will look like commit 958b768a6534ae6e77a8547a56fc31b46b63710b -cd ~/emacs/emacs-25 +cd ~/emacs/emacs-26 git cherry-pick -xe 958b768a6534ae6e77a8547a56fc31b46b63710b and add "Backport:" to the commit string. Then @@ -79,17 +79,17 @@ and add "Backport:" to the commit string. Then git push -Merging emacs-25 to the master +Merging emacs-26 to the master ============================== It is recommended to use the file gitmerge.el in the admin directory -for merging 'emacs-25' into 'master'. It will take care of many +for merging 'emacs-26' into 'master'. It will take care of many things which would otherwise have to be done manually, like ignoring commits that should not land in master, fixing up ChangeLogs and automatically dealing with certain types of conflicts. If you really want to, you can do the merge manually, but then you're on your own. If you still choose to do that, make absolutely sure that you *always* -use the 'merge' command to transport commits from 'emacs-25' to +use the 'merge' command to transport commits from 'emacs-26' to 'master'. *Never* use 'cherry-pick'! If you don't know why, then you shouldn't manually do the merge in the first place; just use gitmerge.el instead. @@ -102,11 +102,11 @@ up-to-date by doing a pull. Then start Emacs with emacs -l admin/gitmerge.el -f gitmerge You'll be asked for the branch to merge, which will default to -'origin/emacs-25', which you should accept. Merging a local tracking +'origin/emacs-26', which you should accept. Merging a local tracking branch is discouraged, since it might not be up-to-date, or worse, contain commits from you which are not yet pushed upstream. -You will now see the list of commits from 'emacs-25' which are not yet +You will now see the list of commits from 'emacs-26' which are not yet merged to 'master'. You might also see commits that are already marked for "skipping", which means that they will be merged with a different merge strategy ('ours'), which will effectively ignore the diff --git a/configure.ac b/configure.ac index eb2c6840402..eba95e2fb84 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ dnl along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. AC_PREREQ(2.65) dnl Note this is parsed by (at least) make-dist and lisp/cedet/ede/emacs.el. -AC_INIT(GNU Emacs, 26.0.60, bug-gnu-emacs@gnu.org) +AC_INIT(GNU Emacs, 27.0.50, bug-gnu-emacs@gnu.org) dnl Set emacs_config_options to the options of 'configure', quoted for the shell, dnl and then quoted again for a C string. Separate options with spaces. diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index 496b43ce1e3..5aa0c77d34c 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -443,6 +443,13 @@ non-@code{nil}, and in programming-language strings if @code{nil} for @code{electric-quote-string} and @code{t} for the other variables. +@vindex electric-quote-replace-double + You can also set the option @code{electric-quote-replace-double} to +a non-@code{nil} value. Then, typing @t{"} insert an appropriate +curved double quote depending on context: @t{“} at the beginning of +the buffer or after a line break, whitespace, opening parenthesis, or +quote character, and @t{”} otherwise. + Electric Quote mode is disabled by default. To toggle it, type @kbd{M-x electric-quote-mode}. To toggle it in a single buffer, use @kbd{M-x electric-quote-local-mode}. To suppress it for a single use, diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index f49b02de97c..0a37eeb2a85 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -2108,7 +2108,7 @@ Note that the @samp{.~3~} in the two last examples is the backup part, not an extension. @end defun -@defun file-name-base &optional filename +@defun file-name-base filename This function is the composition of @code{file-name-sans-extension} and @code{file-name-nondirectory}. For example, @@ -2116,8 +2116,6 @@ and @code{file-name-nondirectory}. For example, (file-name-base "/my/home/foo.c") @result{} "foo" @end example - -The @var{filename} argument defaults to @code{buffer-file-name}. @end defun @node Relative File Names diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi index 3fdc94169bd..be74b0c6111 100644 --- a/doc/lispref/numbers.texi +++ b/doc/lispref/numbers.texi @@ -1107,6 +1107,24 @@ bit is one in the result if, and only if, the @var{n}th bit is zero in @end example @end defun +@cindex popcount +@cindex Hamming weight +@cindex counting set bits +@defun logcount integer +This function returns the @dfn{Hamming weight} of @var{integer}: the +number of ones in the binary representation of @var{integer}. +If @var{integer} is negative, it returns the number of zero bits in +its two's complement binary representation. The result is always +nonnegative. + +@example +(logcount 43) ; 43 = #b101011 + @result{} 4 +(logcount -43) ; -43 = #b111...1010101 + @result{} 3 +@end example +@end defun + @node Math Functions @section Standard Mathematical Functions @cindex transcendental functions diff --git a/doc/misc/trampver.texi b/doc/misc/trampver.texi index 5151ed5354c..5d9dcc5635d 100644 --- a/doc/misc/trampver.texi +++ b/doc/misc/trampver.texi @@ -8,7 +8,7 @@ @c In the Tramp GIT, the version number is auto-frobbed from @c configure.ac, so you should edit that file and run @c "autoconf && ./configure" to change the version number. -@set trampver 2.3.3.26.1 +@set trampver 2.3.3-pre @c Other flags from configuration @set instprefix /usr/local @@ -6,11 +6,12 @@ See the end of the file for license conditions. Please send Emacs bug reports to bug-gnu-emacs@gnu.org. If possible, use M-x report-emacs-bug. -This file is about changes in Emacs version 26. +This file is about changes in Emacs version 27. See file HISTORY for a list of GNU Emacs versions and release dates. -See files NEWS.25, NEWS.24, NEWS.23, NEWS.22, NEWS.21, NEWS.20, -NEWS.19, NEWS.18, and NEWS.1-17 for changes in older Emacs versions. +See files NEWS.26, NEWS.25, NEWS.24, NEWS.23, NEWS.22, NEWS.21, +NEWS.20, NEWS.19, NEWS.18, and NEWS.1-17 for changes in older Emacs +versions. You can narrow news to a specific version by calling 'view-emacs-news' with a prefix argument or by typing C-u C-h C-n. @@ -22,1343 +23,46 @@ Temporary note: When you add a new item, use the appropriate mark if you are sure it applies, -* Installation Changes in Emacs 26.1 - -** By default libgnutls is now required when building Emacs. -Use 'configure --with-gnutls=no' to build even when GnuTLS is missing. - -** GnuTLS version 2.12.2 or later is now required, instead of merely -version 2.6.6 or later. - -** The new option 'configure --with-mailutils' causes Emacs to rely on -GNU Mailutils to retrieve email. It is recommended, and is the -default if GNU Mailutils is installed. When --with-mailutils is not -in effect, the Emacs build procedure by default continues to build and -install a limited 'movemail' substitute that retrieves POP3 email only -via insecure channels; to avoid this problem, use either ---with-mailutils or --without-pop when configuring. - -** The new option 'configure --enable-gcc-warnings=warn-only' causes -GCC to issue warnings without stopping the build. This behavior is -now the default in developer builds. As before, use -'--disable-gcc-warnings' to suppress GCC's warnings, and -'--enable-gcc-warnings' to stop the build if GCC issues warnings. - -** When GCC warnings are enabled, '--enable-check-lisp-object-type' is -now enabled by default when configuring. - -+++ -** The Emacs server now has socket-launching support. This allows -socket based activation, where an external process like systemd can -invoke the Emacs server process upon a socket connection event and -hand the socket over to Emacs. Emacs uses this socket to service -emacsclient commands. This new functionality can be disabled with the -configure option '--disable-libsystemd'. - -+++ -** A systemd user unit file is provided. Use it in the standard way: -systemctl --user enable emacs -(If your Emacs is installed in a non-standard location, you may -need to copy the emacs.service file to eg ~/.config/systemd/user/) - -** New configure option '--disable-build-details' attempts to build an -Emacs that is more likely to be reproducible; that is, if you build -and install Emacs twice, the second Emacs is a copy of the first. -Deterministic builds omit the build date from the output of the -'emacs-version' and 'erc-cmd-SV' functions, and the leave the -following variables nil: 'emacs-build-system', 'emacs-build-time', -'erc-emacs-build-time'. - ---- -** Emacs can now be built with support for Little CMS. - -If the lcms2 library is installed, Emacs will enable features built on -top of that library. The new configure option '--without-lcms2' can -be used to build without lcms2 support even if it is installed. Emacs -linked to Little CMS exposes color management functions in Lisp: the -color metrics 'lcms-cie-de2000' and 'lcms-cam02-ucs', as well as -functions for conversion to and from CIE CAM02 and CAM02-UCS. - -** The configure option '--with-gameuser' now defaults to 'no', -as this appears to be the most common configuration in practice. -When it is 'no', the shared game directory and the auxiliary program -update-game-score are no longer needed and are not installed. - -** Emacs no longer works on IRIX. We expect that Emacs users are not -affected by this, as SGI stopped supporting IRIX in December 2013. +* Installation Changes in Emacs 27.1 -* Startup Changes in Emacs 26.1 - -+++ -** New option '--fg-daemon'. This is the same as '--daemon', except -it runs in the foreground and does not fork. This is intended for -modern init systems such as systemd, which manage many of the traditional -aspects of daemon behavior themselves. '--bg-daemon' is now an alias -for '--daemon'. - -+++ -** New option '--module-assertions'. -When given this option, Emacs will perform expensive correctness -checks when dealing with dynamic modules. This is intended for module -authors that wish to verify that their module conforms to the module -requirements. The option makes Emacs abort if a module-related -assertion triggers. - -+++ -** Emacs now supports 24-bit colors on capable text terminals -Terminal is automatically initialized to use 24-bit colors if the -required capabilities are found in terminfo. See the FAQ node -"Colors on a TTY" for more information. - -+++ -** Emacs now obeys the X resource "scrollBar" at startup. -The effect is similar to that of "toolBar" resource on the tool bar. +* Startup Changes in Emacs 27.1 -* Changes in Emacs 26.1 - -+++ -** Option 'buffer-offer-save' can be set to new value, 'always'. When - set to 'always', the command `save-some-buffers' will always offer - this buffer for saving. - -** Security vulnerability related to Enriched Text mode is removed. - -+++ -*** Enriched Text mode does not evaluate Lisp in 'display' properties. -This feature allows saving 'display' properties as part of text. -Emacs 'display' properties support evaluation of arbitrary Lisp forms -as part of processing the property for display, so displaying Enriched -Text could be vulnerable to executing arbitrary malicious Lisp code -included in the text (e.g., sent as part of an email message). -Therefore, execution of arbitrary Lisp forms in 'display' properties -decoded by Enriched Text mode is now disabled by default. Customize -the new option 'enriched-allow-eval-in-display-props' to a non-nil -value to allow Lisp evaluation in decoded 'display' properties. - -This vulnerability was introduced in Emacs 21.1. To work around that -in Emacs versions before 25.3, append the following to your ~/.emacs -init file: - - (eval-after-load "enriched" - '(defun enriched-decode-display-prop (start end &optional param) - (list start end))) - -+++ -** Functions in 'write-contents-functions' can fully short-circuit the -'save-buffer' process. Previously, saving a buffer that was not -visiting a file would always prompt for a file name. Now it only does -so if 'write-contents-functions' is nil (or all its functions return -nil). - ---- -** New variable 'executable-prefix-env' for inserting magic signatures. -This variable affects the format of the interpreter magic number -inserted by 'executable-set-magic'. If non-nil, the magic number now -takes the form "#!/usr/bin/env interpreter", otherwise the value -determined by 'executable-prefix', which is by default -"#!/path/to/interpreter". By default, 'executable-prefix-env' is nil, -so the default behavior is not changed. - -+++ -** The variable 'emacs-version' no longer includes the build number. -This is now stored separately in a new variable, 'emacs-build-number'. - -+++ -** Emacs now provides a limited form of concurrency with Lisp threads. -Concurrency in Emacs Lisp is "mostly cooperative", meaning that -Emacs will only switch execution between threads at well-defined -times: when Emacs waits for input, during blocking operations related -to threads (such as mutex locking), or when the current thread -explicitly yields. Global variables are shared among all threads, but -a 'let' binding is thread-local. Each thread also has its own current -buffer and its own match data. - -See the chapter "Threads" in the ELisp manual for full documentation -of these facilities. +* Changes in Emacs 27.1 +++ -** The new user variable 'electric-quote-chars' provides a list -of curved quotes for 'electric-quote-mode', allowing user to choose -the types of quotes to be used. - ---- -** The new user option 'electric-quote-context-sensitive' makes -'electric-quote-mode' context sensitive. If it is non-nil, you can -type an ASCII apostrophe to insert an opening or closing quote, -depending on context. Emacs will replace the apostrophe by an opening -quote character at the beginning of the buffer, the beginning of a -line, after a whitespace character, and after an opening parenthesis; -and it will replace the apostrophe by a closing quote character in all -other cases. - ---- -** The new variable 'electric-quote-inhibit-functions' controls when -to disable electric quoting based on context. Major modes can add -functions to this list; Emacs will temporarily disable -'electric-quote-mode' whenever any of the functions returns non-nil. -This can be used by major modes that derive from 'text-mode' but allow -inline code segments, such as 'markdown-mode'. - -+++ -** The new user variable 'dired-omit-case-fold' allows the user to -customize the case-sensitivity of dired-omit-mode. It defaults to -the same sensitivity as that of the filesystem for the corresponding -dired buffer. - -+++ -** Emacs now uses double buffering to reduce flicker when editing and -resizing graphical Emacs frames on the X Window System. This support -requires the DOUBLE-BUFFER extension, which major X servers have -supported for many years. If your system has this extension, but an -Emacs built with double buffering misbehaves on some displays you use, -you can disable the feature by adding - - '(inhibit-double-buffering . t) - -to default-frame-alist. Or inject this parameter into the selected -frame by evaluating this form: - - (modify-frame-parameters nil '((inhibit-double-buffering . t))) - ---- -The group 'wp', whose label was "text", is now deprecated. -Use the new group 'text', which inherits from 'wp', instead. - -+++ -** The new function 'call-shell-region' executes a command in an -inferior shell with the buffer region as input. - -+++ -** The new user option 'shell-command-dont-erase-buffer' controls -if the output buffer is erased between shell commands; if non-nil, -the output buffer is not erased; this variable also controls where -to set the point in the output buffer: beginning of the output, -end of the buffer or save the point. -When 'shell-command-dont-erase-buffer' is nil, the default value, -the behavior of 'shell-command', 'shell-command-on-region' and -'async-shell-command' is as usual. - -+++ -** The new user option 'async-shell-command-display-buffer' controls -whether the output buffer of an asynchronous command is shown -immediately, or only when there is output. - -+++ -** The new user option 'mouse-select-region-move-to-beginning' -controls the position of point when double-clicking mouse-1 on the end -of a parenthetical grouping or string-delimiter: the default value nil -keeps point at the end of the region, setting it to non-nil moves -point to the beginning of the region. - -+++ -** The new user option 'mouse-drag-and-drop-region' allows to drag the -entire region of text to another place or another buffer. - -+++ -** The new user option 'confirm-kill-processes' allows the user to -skip a confirmation prompt for killing subprocesses when exiting -Emacs. When set to t (the default), Emacs will prompt for -confirmation before killing subprocesses on exit, which is the same -behavior as before. - ---- -** 'find-library-name' will now fall back on looking at 'load-history' -to try to locate libraries that have been loaded with an explicit path -outside 'load-path'. - -+++ -** Faces in 'minibuffer-prompt-properties' no longer overwrite properties -in the text in functions like 'read-from-minibuffer', but instead are -added to the end of the face list. This allows users to say things -like '(read-from-minibuffer (propertize "Enter something: " 'face 'bold))'. - -+++ -** The new variable 'extended-command-suggest-shorter' has been added -to control whether to suggest shorter 'M-x' commands or not. - ---- -** icomplete now respects 'completion-ignored-extensions'. - -+++ -** Non-breaking hyphens are now displayed with the 'nobreak-hyphen' -face instead of the 'escape-glyph' face. - -+++ -** Approximations to quotes are now displayed with the new 'homoglyph' -face instead of the 'escape-glyph' face. - -+++ -** New face 'header-line-highlight'. -This face is the header-line analogue of 'mode-line-highlight'; it -should be the preferred mouse-face for mouse-sensitive elements in the -header line. - ---- -** 'C-x h' ('mark-whole-buffer') will now avoid marking the prompt -part of minibuffers. - ---- -** 'fill-paragraph' no longer marks the buffer as changed unless it -actually changed something. - ---- -** The locale language name 'ca' is now mapped to the language -environment 'Catalan', which has been added. - ---- -** 'align-regexp' has a separate history for its interactive argument. -'align-regexp' no longer shares its history with all other -history-less functions that use 'read-string'. - -+++ -** The networking code has been reworked so that it's more -asynchronous than it was (when specifying :nowait t in -'make-network-process'). How asynchronous it is varies based on the -capabilities of the system, but on a typical GNU/Linux system the DNS -resolution, the connection, and (for TLS streams) the TLS negotiation -are all done without blocking the main Emacs thread. To get -asynchronous TLS, the TLS boot parameters have to be passed in (see -the manual for details). - -Certain process oriented functions (like 'process-datagram-address') -will block until socket setup has been performed. The recommended way -to deal with asynchronous sockets is to avoid interacting with them -until they have changed status to "run". This is most easily done -from a process sentinel. - ---- -** 'make-network-process' and 'open-network-stream' sometimes allowed -:service to be an integer string (e.g., :service "993") and sometimes -required an integer (e.g., :service 993). This difference has been -eliminated, and integer strings work everywhere. - ---- -** It is possible to disable attempted recovery on fatal signals. -Two new variables support disabling attempts to recover from stack -overflow and to avoid automatic auto-save when Emacs is delivered a -fatal signal. 'attempt-stack-overflow-recovery', if set to 'nil', -will disable attempts to recover from C stack overflows; Emacs will -then crash as with any other fatal signal. -'attempt-orderly-shutdown-on-fatal-signal', if set to 'nil', will -disable attempts to auto-save the session and shut down in an orderly -fashion when Emacs receives a fatal signal; instead, Emacs will -terminate immediately. Both variables are non-'nil' by default. -These variables are for users who would like to avoid the small -probability of data corruption due to techniques Emacs uses to recover -in these situations. - -+++ -** File local and directory local variables are now initialized each -time the major mode is set, not just when the file is first visited. -These local variables will thus not vanish on setting a major mode. - -+++ -** A second dir-local file (.dir-locals-2.el) is now accepted. -See the variable 'dir-locals-file-2' for more information. - -+++ -** Connection-local variables can be used to specify local variables -with a value depending on the connected remote server. For details, -see the node "Connection Local Variables" in the ELisp manual. - ---- -** International domain names (IDNA) are now encoded via the new -puny.el library, so that one can visit Web sites with non-ASCII URLs. - -+++ -** The new 'list-timers' command lists all active timers in a buffer, -where you can cancel them with the 'c' command. - -+++ -** 'switch-to-buffer-preserve-window-point' now defaults to t. - -+++ -** The new variable 'debugger-stack-frame-as-list' allows displaying -all call stack frames in a Lisp backtrace buffer as lists. Both -debug.el and edebug.el have been updated to heed to this variable. - ---- -** Values in call stack frames are now displayed using 'cl-prin1'. -The old behaviour of using 'prin1' can be restored by customizing the -new option 'debugger-print-function'. - -+++ -** NUL bytes in text copied to the system clipboard are now replaced with "\0". - -+++ -** The new variable 'x-ctrl-keysym' has been added to the existing -roster of X keysyms. It can be used in combination with another -variable of this kind to swap modifiers in Emacs. - ---- -** New input methods: 'cyrillic-tuvan', 'polish-prefix'. - ---- -** The 'dutch' input method no longer attempts to support Turkish too. -Also, it no longer converts 'IJ' and 'ij' to the compatibility -characters U+0132 LATIN CAPITAL LIGATURE IJ and U+0133 LATIN SMALL -LIGATURE IJ. - -+++ -** File name quoting by adding the prefix "/:" is now possible for the -local part of a remote file name. Thus, if you have a directory named -"/~" on the remote host "foo", you can prevent it from being -substituted by a home directory by writing it as "/foo:/:/~/file". - -+++ -** The new variable 'maximum-scroll-margin' allows having effective -settings of 'scroll-margin' up to half the window size, instead of -always restricting the margin to a quarter of the window. - -+++ -** Emacs can scroll horizontally using mouse, touchpad, and trackbar. -You can enable this by customizing 'mwheel-tilt-scroll-p'. If you -want to reverse the direction of the scroll, customize -'mwheel-flip-direction'. - -+++ -** Emacsclient has a new option -u/--suppress-output. -This option suppresses display of return values from the server -process. - -+++ -** Emacsclient has a new option -T/--tramp. -This helps with using a local Emacs session as the server for a remote -emacsclient. With appropriate setup, one can now set the EDITOR -environment variable on a remote machine to emacsclient, and -use the local Emacs to edit remote files via Tramp. See the node -"emacsclient Options" in the user manual for the details. - ---- -** New user option 'dig-program-options' and extended functionality -for DNS-querying functions 'nslookup-host', 'dns-lookup-host', -and 'run-dig'. Each function now accepts an optional name server -argument interactively (with a prefix argument) and non-interactively. - -+++ -** 'describe-key-briefly' now ignores mouse movement events. - -+++ -** The new variable 'eval-expression-print-maximum-character' prevents -large integers from being displayed as characters by 'M-:' and similar -commands. - ---- -** Two new commands for finding the source code of Emacs Lisp -libraries: 'find-library-other-window' and 'find-library-other-frame'. - -+++ -** The new variable 'display-raw-bytes-as-hex' allows to change the -display of raw bytes from octal to hex. - -+++ -** You can now provide explicit field numbers in format specifiers. -For example, '(format "%2$s %1$s" "X" "Y")' produces "Y X". - -+++ -** Emacs now supports optional display of line numbers in the buffer. -This is similar to what linum-mode provides, but much faster and -doesn't usurp the display margin for the line numbers. Customize the -buffer-local variable 'display-line-numbers' to activate this optional -display. Alternatively, you can use the `display-line-numbers-mode' -minor mode or the global `global-display-line-numbers-mode'. When -using these modes, customize `display-line-numbers-type' with the same -value as you would use with `display-line-numbers'. - -Line numbers are not displayed at all in minibuffer windows and in -tooltips, as they are not useful there. - -Lisp programs can disable line-number display for a particular screen -line by putting the 'display-line-numbers-disable' text property or -overlay property on the first character of that screen line. This is -intended for add-on packages that need a finer control of the display. - -Lisp programs that need to know how much screen estate is used up for -line-number display in a window can use the new function -'line-number-display-width'. - -Linum mode and all similar packages are henceforth becoming obsolete. -Users and developers are encouraged to switch to this new feature -instead. - -+++ -** emacsclient now accepts command-line options in ALTERNATE_EDITOR -and --alternate-editor. For example, ALTERNATE_EDITOR="emacs -Q -nw". -Arguments may be quoted "like this", so that for example an absolute -path containing a space may be specified; quote escaping is not -supported. +** New function 'logcount' calculates an integer's Hamming weight. -* Editing Changes in Emacs 26.1 - -+++ -** New variable 'column-number-indicator-zero-based'. -Traditionally, in Column Number mode, the displayed column number -counts from zero starting at the left margin of the window. This -behavior is now controlled by 'column-number-indicator-zero-based'. -If you would prefer for the displayed column number to count from one, -you may set this variable to nil. (Behind the scenes, there is now a -new mode line construct, '%C', which operates exactly as '%c' does -except that it counts from one.) - -+++ -** New single-line horizontal scrolling mode. -The 'auto-hscroll-mode' variable can now have a new special value, -'current-line', which causes only the line where the cursor is -displayed to be horizontally scrolled when lines are truncated on -display and point moves outside the left or right window margin. - -+++ -** New mode line constructs '%o' and '%q', and user option -'mode-line-percent-position'. '%o' displays the "degree of travel" of -the window through the buffer. Unlike the default '%p', this -percentage approaches 100% as the window approaches the end of the -buffer. '%q' displays the percentage offsets of both the start and -the end of the window, e.g. "5-17%". The new option -'mode-line-percent-position' makes it easier to switch between '%p', -'%P', and these new constructs. - -+++ -** Two new user options 'list-matching-lines-jump-to-current-line' and -'list-matching-lines-current-line-face' to show highlighted the current -line in *Occur* buffer. - -+++ -** The 'occur' command can now operate on the region. - -+++ -** New bindings for 'query-replace-map'. -'undo', undo the last replacement; bound to 'u'. -'undo-all', undo all replacements; bound to 'U'. - ---- -** 'delete-trailing-whitespace' deletes whitespace after form feed. -In modes where form feed was treated as a whitespace character, -'delete-trailing-whitespace' would keep lines containing it unchanged. -It now deletes whitespace after the last form feed thus behaving the -same as in modes where the character is not whitespace. - ---- -** Emacs no longer prompts about editing a changed file when the file's -content is unchanged. Instead of only checking the modification time, -Emacs now also checks the file's actual content before prompting the user. - ---- -** Various casing improvements. - -*** 'upcase', 'upcase-region' et al. convert title case characters -(such as Dz) into their upper case form (such as DZ). - -*** 'capitalize', 'upcase-initials' et al. make use of title-case forms -of initial characters (correctly producing for example Džungla instead -of incorrect DŽungla). - -*** Characters which turn into multiple ones when cased are correctly handled. -For example, fi ligature is converted to FI when upper cased. - -*** Greek small sigma is correctly handled when at the end of the word. -Strings such as ΌΣΟΣ are now correctly converted to Όσος when -capitalized instead of incorrect Όσοσ (compare lowercase sigma at the -end of the word). - -+++ -** Emacs can now auto-save buffers to visited files in a more robust -manner via the new mode 'auto-save-visited-mode'. Unlike -'auto-save-visited-file-name', this mode uses the normal saving -procedure and therefore obeys saving hooks. -'auto-save-visited-file-name' is now obsolete. - -+++ -** New behavior of 'mark-defun'. -Prefix argument selects that many (or that many more) defuns. -Negative prefix arg flips the direction of selection. Also, -'mark-defun' between defuns correctly selects N following defuns (or --N previous for negative arguments). Finally, comments preceding the -defun are selected unless they are separated from the defun by a blank -line. - -** New command 'replace-buffer-contents'. -This command replaces the contents of the accessible portion of the -current buffer with the contents of the accessible portion of a -different buffer while keeping point, mark, markers, and text -properties as intact as possible. - -+++ -** New commands 'apropos-local-variable' and 'apropos-local-value. -These are buffer-local versions of 'apropos-variable' and -'apropos-value', respectively. They show buffer-local variables whose -names and values, respectively, match a given pattern. - -+++ -** More user control of reordering bidirectional text for display. -The two new variables, 'bidi-paragraph-start-re' and -'bidi-paragraph-separate-re', allow customization of what exactly are -paragraphs, for the purposes of bidirectional display. +* Editing Changes in Emacs 27.1 --- ** New variable 'x-wait-for-event-timeout'. This controls how long Emacs will wait for updates to the graphical state to take effect (making a frame visible, for example). - -* Changes in Specialized Modes and Packages in Emacs 26.1 - ---- -** New function `cl-generic-p'. - -** Dired - -+++ -*** You can answer 'all' in 'dired-do-delete' to delete recursively all -remaining directories without more prompts. - -+++ -*** Dired supports wildcards in the directory part of the file names. - -+++ -*** You can now use '`?`' in 'dired-do-shell-command'. -It gets replaced by the current file name, like ' ? '. - -+++ -*** A new option 'dired-always-read-filesystem' default to nil. -If non-nil, buffers visiting files are reverted before search them; -for instance, in 'dired-mark-files-containing-regexp' a non-nil value -of this option means the file is revisited in a temporary buffer; -this temporary buffer is the actual buffer searched: the original buffer -visiting the file is not modified. - ---- -*** Users can now customize mouse clicks in Dired in a more flexible way. -The new command 'dired-mouse-find-file' can be bound to a mouse click -and used to visit files/directories in Dired in the selected window. -The new command 'dired-mouse-find-file-other-frame' similarly visits -files/directories in another frame. You can write your own commands -that invoke 'dired-mouse-find-file' with non-default optional -arguments, to tailor the effects of mouse clicks on file names in -Dired buffers. - -+++ -*** In wdired, when editing files to contain slash characters, -the resulting directories are automatically created. Whether to do -this is controlled by the 'wdired-create-parent-directories' variable. - +++ -*** 'W' is now bound to 'browse-url-of-dired-file', and is useful for -viewing HTML files and the like. - ---- -*** New variable 'dired-clean-confirm-killing-deleted-buffers' -controls whether Dired asks to kill buffers visiting deleted files and -directories. The default is t, so Dired asks for confirmation, to -keep previous behavior. - ---- -** html2text is now marked obsolete. - ---- -** smerge-refine-regions can refine regions in separate buffers - ---- -** Info menu and index completion uses substring completion by default. -This can be customized via the info-menu category in -completion-category-override. - -+++ -** The ancestor buffer is shown by default in 3-way merges. -A new option ediff-show-ancestor and a new toggle -ediff-toggle-show-ancestor. - ---- -** TeX: Add luatex and xetex as alternatives to pdftex - -** Electric-Buffer-menu - -+++ -*** Key 'U' is bound to 'Buffer-menu-unmark-all' and key 'M-DEL' is -bound to 'Buffer-menu-unmark-all-buffers'. - -** bs - ---- -*** Two new commands 'bs-unmark-all', bound to 'U', and -'bs-unmark-previous', bound to <backspace>. - -** Buffer-menu - -+++ -*** Two new commands 'Buffer-menu-unmark-all', bound to 'U' and -'Buffer-menu-unmark-all-buffers', bound to 'M-DEL'. - ---- -** Checkdoc - -*** 'checkdoc-arguments-in-order-flag' now defaults to nil. - -** Gnus - ---- -*** The .newsrc file will now only be saved if the native select -method is an NNTP select method. - -+++ -*** A new command for sorting articles by readedness marks has been -added: 'C-c C-s C-m C-m'. - -+++ - -*** In message-citation-line-format the %Z format is now the time zone name -instead of the numeric form. The %z format continues to be the -numeric form. The new behavior is compatible with format-time-string. - -** Ibuffer - ---- -*** New command 'ibuffer-jump'. - ---- -*** New filter commands 'ibuffer-filter-by-basename', -'ibuffer-filter-by-file-extension', 'ibuffer-filter-by-directory', -'ibuffer-filter-by-starred-name', 'ibuffer-filter-by-modified' -and 'ibuffer-filter-by-visiting-file'; bound respectively -to '/b', '/.', '//', '/*', '/i' and '/v'. - ---- -*** Two new commands 'ibuffer-filter-chosen-by-completion' -and 'ibuffer-and-filter', the second bound to '/&'. - ---- -*** The commands 'ibuffer-pop-filter', 'ibuffer-pop-filter-group', -'ibuffer-or-filter' and 'ibuffer-filter-disable' have the alternative -bindings '/<up>', '/S-<up>', '/|' and '/DEL', respectively. - ---- -*** The data format specifying filters has been extended to allow -explicit logical 'and', and a more flexible form for logical 'not'. -See 'ibuffer-filtering-qualifiers' doc string for full details. - ---- -*** A new command 'ibuffer-copy-buffername-as-kill'; bound -to 'B'. - ---- -*** New command 'ibuffer-change-marks'; bound to '* c'. - ---- -*** A new command 'ibuffer-mark-by-locked' to mark -all locked buffers; bound to '% L'. - ---- -*** A new option 'ibuffer-locked-char' to indicate -locked buffers; Ibuffer shows a new column displaying -'ibuffer-locked-char' for locked buffers. - ---- -*** A new command 'ibuffer-unmark-all-marks' to unmark -all buffers without asking confirmation; bound to -'U'; 'ibuffer-do-replace-regexp' bound to 'r'. - ---- -*** A new command 'ibuffer-mark-by-content-regexp' to mark buffers -whose content matches a regexp; bound to '% g'. - ---- -*** Two new options 'ibuffer-never-search-content-name' and -'ibuffer-never-search-content-mode' used by -'ibuffer-mark-by-content-regexp'. - -** Browse-URL - ---- -*** Support for opening links to man pages in Man or WoMan mode. - -** Comint - ---- -*** New user option 'comint-move-point-for-matching-input' to control -where to place point after C-c M-r and C-c M-s. - -** Compilation mode - ---- -*** Messages from CMake are now recognized. - -+++ -*** The number of errors, warnings, and informational messages is now -displayed in the mode line. These are updated as compilation -proceeds. - -** Grep - ---- -*** Grep commands will now use GNU grep's '--null' option if -available, which allows distinguishing the filename from contents if -they contain colons. This can be controlled by the new custom option -'grep-use-null-filename-separator'. - ---- -*** The grep/rgrep/lgrep functions will now ask about saving files -before running. This is controlled by the 'grep-save-buffers' -variable. - -** Edebug - ---- -*** Edebug can be prevented from pausing 1 second after reaching a -breakpoint (e.g. with "f" and "o") by customizing the new option -'edebug-sit-on-break'. - -+++ -*** New customizable option 'edebug-max-depth' -This allows to enlarge the maximum recursion depth when instrumenting -code. - -** Eshell - ---- -*** 'eshell-input-filter's value is now a named function -'eshell-input-filter-default', and has a new custom option -'eshell-input-filter-initial-space' to ignore adding commands prefixed -with blank space to eshell history. - -** eww - -+++ -*** New 'M-RET' command for opening a link at point in a new eww buffer. - -+++ -*** A new 's' command for switching to another eww buffer via the minibuffer. - ---- -*** The 'o' command ('shr-save-contents') has moved to 'O' to avoid collision -with the 'o' command from 'image-map'. - -+++ -*** A new command 'C' ('eww-toggle-colors') can be used to toggle -whether to use the HTML-specified colors or not. The user can also -customize the 'shr-use-colors' variable. - ---- -*** Images that are being loaded are now marked with gray -"placeholder" images of the size specified by the HTML. They are then -replaced by the real images asynchronously, which will also now -respect width/height HTML specs (unless they specify widths/heights -bigger than the current window). - ---- -*** The 'w' command on links is now 'shr-maybe-probe-and-copy-url'. -'shr-copy-url' now only copies the url at point; users who wish to -avoid accidentally accessing remote links may rebind 'w' and 'u' in -'eww-link-keymap' to it. - - -** Ido - ---- -*** The commands 'find-alternate-file-other-window', -'dired-other-window', 'dired-other-frame', and -'display-buffer-other-window' are now remapped to Ido equivalents if -Ido mode is active. - -** Images - -+++ -*** Images are automatically scaled before displaying based on the -'image-scaling-factor' variable (if Emacs supports scaling the images -in question). - -+++ -*** It's now possible to specify aspect-ratio preserving combinations -of :width/:max-height and :height/:max-width keywords. In either -case, the "max" keywords win. (Previously some combinations would, -depending on the aspect ratio of the image, just be ignored and in -other instances this would lead to the aspect ratio not being -preserved.) - -+++ -*** Images inserted with 'insert-image' and related functions get a -keymap put into the text properties (or overlays) that span the -image. This keymap binds keystrokes for manipulating size and -rotation, as well as saving the image to a file. These commands are -also available in 'image-mode'. - -+++ -*** A new library for creating and manipulating SVG images has been -added. See the "SVG Images" section in the Lisp reference manual for -details. - -+++ -*** New setf-able function to access and set image parameters is -provided: 'image-property'. - ---- -*** New commands 'image-scroll-left' and 'image-scroll-right' -for 'image-mode' that complement 'image-scroll-up' and -'image-scroll-down': they have the same prefix arg behavior and stop -at image boundaries. - -** Image-Dired - ---- -*** Now provides a minor mode 'image-dired-minor-mode' which replaces -the function 'image-dired-setup-dired-keybindings'. - ---- -*** Thumbnail generation is now asynchronous. -The number of concurrent processes is limited by the variable -'image-dired-thumb-job-limit'. - ---- -*** 'image-dired-thumbnail-storage' has a new option 'standard-large' -for generating 256x256 thumbnails according to the Thumbnail Managing -Standard. - ---- -*** Inherits movement keys from 'image-mode' for viewing full images. -This includes the usual char, line, and page movement commands. - ---- -*** All the -options types have been changed to argument lists -instead of shell command strings. This change affects -'image-dired-cmd-create-thumbnail-options', -'image-dired-cmd-create-temp-image-options', -'image-dired-cmd-rotate-thumbnail-options', -'image-dired-cmd-rotate-original-options', -'image-dired-cmd-write-exif-data-options', -'image-dired-cmd-read-exif-data-options', and introduces -'image-dired-cmd-pngnq-options', 'image-dired-cmd-pngcrush-options', -'image-dired-cmd-create-standard-thumbnail-options' - ---- -*** Recognizes more tools by default, including pngnq-s9 and OptiPNG - ---- -*** 'find-file' and related commands now work on thumbnails and -displayed images, providing a default argument of the original file name -via an addition to 'file-name-at-point-functions'. - ---- -** The default 'Info-default-directory-list' no longer checks some obsolete -directory suffixes (gnu, gnu/lib, gnu/lib/emacs, emacs, lib, lib/emacs) -when searching for info directories. - -+++ -** The commands that add ChangeLog entries now prefer a VCS root directory -for the ChangeLog file, if none already exists. Customize -'change-log-directory-files' to nil for the old behavior. - ---- -** Support for non-string values of 'time-stamp-format' has been removed. - -** Message - ---- -*** 'message-use-idna' now defaults to t (because Emacs comes with -built-in IDNA support now). - ---- -*** When sending HTML messages with embedded images, and you have -exiftool installed, and you rotate images with EXIF data (i.e., -JPEGs), the rotational information will be inserted into the outgoing -image in the message. (The original image will not have its -orientation affected.) - ---- -*** The 'message-valid-fqdn-regexp' variable has been removed, since -there are now top-level domains added all the time. Message will no -longer warn about sending emails to top-level domains it hasn't heard -about. - -*** 'message-beginning-of-line' (bound to C-a) understands folded headers. -In 'visual-line-mode' it will look for the true beginning of a header -while in non-'visual-line-mode' it will move the point to the indented -header's value. - -** Package - -+++ -*** The new variable 'package-gnupghome-dir' has been added to control -where the GnuPG home directory (used for signature verification) is -located and whether GnuPG's option "--homedir" is used or not. - ---- -*** Deleting a package no longer respects 'delete-by-moving-to-trash'. - -** Tramp - -+++ -*** The method part of remote file names is mandatory now. -A valid remote file name starts with "/method:host:" or -"/method:user@host:". - -+++ -*** The new pseudo method "-" is a marker for the default method. -"/-::" is the shortest remote file name then. - -+++ -*** The command 'tramp-change-syntax' allows to choose an alternative -remote file name syntax. - -+++ -*** New connection method "sg", which supports editing files under a -different group ID. - -+++ -*** New connection method "doas" for OpenBSD hosts. - -+++ -*** New connection method "gdrive", which allows to access Google -Drive onsite repositories. - -+++ -*** Gateway methods in Tramp have been removed. -Instead, the Tramp manual documents how to configure ssh and PuTTY -accordingly. - -+++ -*** Setting the "ENV" environment variable in -'tramp-remote-process-environment' enables reading of shell -initialization files. - ---- -*** Tramp is able now to send SIGINT to remote asynchronous processes. - ---- -*** Variable 'tramp-completion-mode' is obsoleted. - ---- -** 'auto-revert-use-notify' is set back to t in 'global-auto-revert-mode'. - -** JS mode - ---- -*** JS mode now sets 'comment-multi-line' to t. - ---- -*** New variable 'js-indent-align-list-continuation', when set to nil, -will not align continuations of bracketed lists, but will indent them -by the fixed width 'js-indent-level'. - -** CSS mode - ---- -*** Support for completing attribute values, at-rules, bang-rules, -HTML tags, classes and IDs using the 'completion-at-point' command. -Completion candidates for HTML classes and IDs are retrieved from open -HTML mode buffers. - ---- -*** CSS mode now binds 'C-h S' to a function that will show -information about a CSS construct (an at-rule, property, pseudo-class, -pseudo-element, with the default being guessed from context). By -default the information is looked up on the Mozilla Developer Network, -but this can be customized using 'css-lookup-url-format'. - ---- -*** CSS colors are fontified using the color they represent as the -background. For instance, #ff0000 would be fontified with a red -background. - -+++ -** Emacs now supports character name escape sequences in character and -string literals. The syntax variants \N{character name} and -\N{U+code} are supported. - -+++ -** Prog mode has some support for multi-mode indentation. -This allows better indentation support in modes that support multiple -programming languages in the same buffer, like literate programming -environments or ANTLR programs with embedded Python code. - -A major mode can provide indentation context for a sub-mode through -the 'prog-indentation-context' variable. To support this, modes that -provide indentation should use 'prog-widen' instead of 'widen' and -'prog-first-column' instead of a literal zero. See the node -"Mode-Specific Indent" in the ELisp manual for more details. - -** ERC - ---- -*** New variable 'erc-default-port-tls' used to connect to TLS IRC -servers. - -** URL - -+++ -*** The new function 'url-cookie-delete-cookie' can be used to -programmatically delete all cookies, or cookies from a specific -domain. - -+++ -*** 'url-retrieve-synchronously' now takes an optional timeout parameter. - ---- -*** The URL package now support HTTPS over proxies supporting CONNECT. - -+++ -*** 'url-user-agent' now defaults to 'default', and the User-Agent -string is computed dynamically based on 'url-privacy-level'. - -** VC and related modes - ---- -*** The VC state indicator in the mode line now defaults to more -colorful faces to make it more obvious to the user what the state is. -See the 'vc-faces' customization group. - -+++ -*** 'vc-dir-mode' now binds 'vc-log-outgoing' to 'O'; and has various -branch-related commands on a keymap bound to 'B'. - ---- -*** 'vc-region-history' is now bound to 'C-x v h', replacing the older -'vc-insert-headers' binding. - -** CC mode - ---- -*** Opening a .h file will turn C or C++ mode depending on language used. -This is done with the help of 'c-or-c++-mode' function which analyses -contents of the buffer to determine whether it's a C or C++ source -file. - ---- -** New DNS mode command 'dns-mode-ipv6-to-nibbles' to convert IPv6 addresses -to a format suitable for reverse lookup zone files. - -** Ispell - -+++ -*** Enchant is now supported as a spell-checker. - -Enchant is a meta-spell-checker that uses providers -such as Hunspell to do the actual checking. With it, users can use -spell-checkers not directly supported by Emacs, such as Voikko, Hspell -and AppleSpell, more easily share personal word-lists with other -programs, and configure different spelling-checkers for different -languages. (Version 2.1.0 or later of Enchant is required.) - -** Flymake - -+++ -*** Emacs no longer prompts the user before killing Flymake processes on exit. +** The new user option 'electric-quote-replace-double' controls +whether " is also replaced in 'electric-quote-mode'. If non-nil, " is +replaced by a double typographic quote. -* New Modes and Packages in Emacs 26.1 - -** New Elisp data-structure library 'radix-tree'. +* Changes in Specialized Modes and Packages in Emacs 27.1 -** New library 'xdg' with utilities for some XDG standards and specs. +** Enhanced xterm support -** HTML - -+++ -*** A new submode of 'html-mode', 'mhtml-mode', is now the default -mode for *.html files. This mode handles indentation, -fontification, and commenting for embedded JavaScript and CSS. - -** New mode 'conf-toml-mode' is a sub-mode of conf-mode, specialized - for editing TOML files. - -** New mode 'conf-desktop-mode' is a sub-mode of conf-unix-mode, -specialized for editing freedesktop.org desktop entries. - -** New minor mode 'pixel-scroll-mode' provides smooth pixel-level scrolling. - -** New major mode 'less-css-mode' (a minor variant of 'css-mode') for -editing Less files. +*** New variable 'xterm-set-window-title' controls whether Emacs +sets the XTerm window title. The default is to set the window title. -* Incompatible Lisp Changes in Emacs 26.1 +* New Modes and Packages in Emacs 27.1 ---- -*** password-data is now a hash-table -so that `password-read' can use any object for the `key' argument. - -+++ -*** Command 'dired-mark-extension' now automatically prepends a '.' to the -extension when not present. The new command 'dired-mark-suffix' behaves -similarly but it doesn't prepend a '.'. - -+++ -** Certain cond/pcase/cl-case forms are now compiled using a faster jump -table implementation. This uses a new bytecode op 'switch', which -isn't compatible with previous Emacs versions. This functionality can -be disabled by setting 'byte-compile-cond-use-jump-table' to nil. - ---- -** The alist 'ucs-names' is now a hash table. - ---- -** 'if-let' and 'when-let' are subsumed by 'if-let*' and 'when-let*'. -The incumbent 'if-let' and 'when-let' are now marked obsolete. -'if-let*' and 'when-let*' do not accept the single tuple special case. -New macro 'and-let*' is an implementation of the Scheme SRFI-2 syntax -of the same name. 'if-let*' and 'when-let*' now accept the same -binding syntax as 'and-let*'. - ---- -** 'C-up', 'C-down', 'C-left' and 'C-right' are now defined in term -mode to send the same escape sequences that xterm does. This makes -things like forward-word in readline work. - ---- -** hideshow mode got four key bindings that are analogous to outline -mode bindings: 'C-c @ C-a', 'C-c @ C-t', 'C-c @ C-d', and 'C-c @ C-e.' - ---- -** Customizable variable 'query-replace-from-to-separator' -now doesn't propertize the string value of the separator. -Instead, text properties are added by query-replace-read-from. -Additionally, the new nil value restores pre-24.5 behavior -of not providing replacement pairs via the history. - ---- -** Some obsolete functions, variables, and faces have been removed: -*** make-variable-frame-local. Variables cannot be frame-local any more. -*** From subr.el: window-dot, set-window-dot, read-input, show-buffer, -eval-current-buffer, string-to-int -*** icomplete-prospects-length. -*** All the default-FOO variables that hold the default value of the -FOO variable. Use 'default-value' and 'setq-default' to access and -change FOO, respectively. The exhaustive list of removed variables is: -'default-mode-line-format', 'default-header-line-format', -'default-line-spacing', 'default-abbrev-mode', 'default-ctl-arrow', -'default-truncate-lines', 'default-left-margin', 'default-tab-width', -'default-case-fold-search', 'default-left-margin-width', -'default-right-margin-width', 'default-left-fringe-width', -'default-right-fringe-width', 'default-fringes-outside-margins', -'default-scroll-bar-width', 'default-vertical-scroll-bar', -'default-indicate-empty-lines', 'default-indicate-buffer-boundaries', -'default-fringe-indicator-alist', 'default-fringe-cursor-alist', -'default-scroll-up-aggressively', 'default-scroll-down-aggressively', -'default-fill-column', 'default-cursor-type', -'default-cursor-in-non-selected-windows', -'default-buffer-file-coding-system', 'default-major-mode', and -'default-enable-multibyte-characters'. -*** Many variables obsoleted in 22.1 referring to face symbols - -+++ -** The variable 'text-quoting-style' is now a customizable option. It -controls whether to and how to translate ASCII quotes in messages and -help output. Its possible values and their semantics remain unchanged -from Emacs 25. In particular, when this variable's value is 'grave', -all quotes in formats are output as-is. - ---- -** Functions like 'check-declare-file' and 'check-declare-directory' -now generate less chatter and more-compact diagnostics. The auxiliary -function 'check-declare-errmsg' has been removed. - -+++ -** The regular expression character class [:blank:] now matches -Unicode horizontal whitespace as defined in the Unicode Technical -Standard #18. If you only want to match space and tab, use [ \t] -instead. - -+++ -** 'min' and 'max' no longer round their results. -Formerly, they returned a floating-point value if any argument was -floating-point, which was sometimes numerically incorrect. For -example, on a 64-bit host (max 1e16 10000000000000001) now returns its -second argument instead of its first. - -+++ -** The variable 'old-style-backquotes' has been made internal and -renamed to 'lread--old-style-backquotes'. No user code should use -this variable. - ---- -** To avoid confusion caused by "smart quotes", the reader no longer -accepts Lisp symbols which begin with the following quotation -characters: ‘’‛“”‟〞"', unless they are escaped with backslash. - -+++ -** 'default-file-name-coding-system' now defaults to a coding system -that does not process CRLF. For example, it defaults to utf-8-unix -instead of to utf-8. Before this change, Emacs would sometimes -mishandle file names containing these control characters. - -+++ -** 'file-attributes', 'file-symlink-p' and 'make-symbolic-link' no -longer quietly mutate the target of a local symbolic link, so that -Emacs can access and copy them reliably regardless of their contents. -The following changes are involved. - ---- -*** 'file-attributes' and 'file-symlink-p' no longer prepend "/:" to -symbolic links whose targets begin with "/" and contain ":". For -example, if a symbolic link "x" has a target "/y:z:", '(file-symlink-p -"x")' now returns "/y:z:" rather than "/:/y:z:". - ---- -*** 'make-symbolic-link' no longer looks for file name handlers of -target when creating a symbolic link. For example, -'(make-symbolic-link "/y:z:" "x")' now creates a symbolic link to -"/y:z:" instead of failing. - -+++ -*** 'make-symbolic-link' removes the remote part of a link target if -target and newname have the same remote part. For example, -'(make-symbolic-link "/x:y:a" "/x:y:b")' creates a link with the -literal string "a"; and '(make-symbolic-link "/x:y:a" "/x:z:b")' -creates a link with the literal string "/x:y:a" instead of failing. - -+++ -*** 'make-symbolic-link' now expands a link target with leading "~" -only when the optional third arg is an integer, as when invoked -interactively. For example, '(make-symbolic-link "~y" "x")' now -creates a link with target the literal string "~y"; to get the old -behavior, use '(make-symbolic-link (expand-file-name "~y") "x")'. To -avoid this expansion in interactive use, you can now prefix the link -target with "/:". For example, '(make-symbolic-link "/:~y" "x" 1)' -now creates a link to literal "~y". - -+++ -** 'file-truename' returns a quoted file name if the target of a -symbolic link has remote file name syntax. - -+++ -** Module functions are now implemented slightly differently; in -particular, the function 'internal--module-call' has been removed. -Code that depends on undocumented internals of the module system might -break. - ---- -** The argument LOCKNAME of 'write-region' is propagated to file name -handlers now. - ---- -** When built against recent versions of GTK+, Emacs always uses -gtk_window_move for moving frames and ignores the value of the -variable 'x-gtk-use-window-move'. The variable is now obsolete. - -+++ -** Several functions that create or rename files now treat their -destination argument specially only when it is a directory name, i.e., -when it ends in '/' on GNU and other POSIX-like systems. When the -destination argument D of one of these functions is an existing -directory and the intent is to act on an entry in that directory, D -should now be a directory name. For example, (rename-file "e" "f/") -renames to 'f/e'. Although this formerly happened sometimes even when -D was not a directory name, as in (rename-file "e" "f") where 'f' -happened to be a directory, the old behavior often contradicted the -documentation and had inherent races that led to security holes. A -call like (rename-file C D) that used the old, undocumented behavior -can be written as (rename-file C (file-name-as-directory D)), a -formulation portable to both older and newer versions of Emacs. -Affected functions include add-name-to-file, copy-directory, -copy-file, format-write-file, gnus-copy-file, make-symbolic-link, -rename-file, thumbs-rename-images, and write-file. + +* Incompatible Lisp Changes in Emacs 27.1 ---- -** The list returned by 'overlays-at' is now in decreasing priority order. -The documentation of this function always said the order should be -that of decreasing priority, if the 2nd argument of the function is -non-nil, but the code returned the list in the increasing order of -priority instead. Now the code does what the documentation says it -should do. +** The FILENAME argument to 'file-name-base' is now mandatory and no +longer defaults to 'buffer-file-name'. --- ** The function 'eldoc-message' now accepts a single argument. @@ -1367,549 +71,10 @@ them through 'format' first. Even that is discouraged: for ElDoc support, you should set 'eldoc-documentation-function' instead of calling 'eldoc-message' directly. -* Lisp Changes in Emacs 26.1 - -+++ -** The function 'assoc' now takes an optional third argument TESTFN. -This argument, when non-nil, is used for comparison instead of -'equal'. - -+++ -** New optional argument TESTFN in 'alist-get', 'map-elt' and 'map-put'. -If non-nil, the argument specifies a function to use for comparison, -instead of, respectively, 'assq' and 'eql'. - -+++ -** New function 'seq-set-equal-p' to check if SEQUENCE1 and SEQUENCE2 -contain the same elements, regardless of the order. - -+++ -** The new function 'mapbacktrace' applies a function to all frames of -the current stack trace. - -+++ -** The new function 'file-name-case-insensitive-p' tests whether a -given file is on a case-insensitive filesystem. - -+++ -** Several accessors for the value returned by 'file-attributes' -have been added. They are: 'file-attribute-type', -'file-attribute-link-number', 'file-attribute-user-id', -'file-attribute-group-id', 'file-attribute-access-time', -'file-attribute-modification-time', -'file-attribute-status-change-time', 'file-attribute-size', -'file-attribute-modes', 'file-attribute-inode-number', -'file-attribute-device-number' and 'file-attribute-collect'. - -+++ -** The new function 'buffer-hash' computes a fast, non-consing hash of -a buffer's contents. - -+++ -** 'interrupt-process' now consults the list 'interrupt-process-functions', -to determine which function has to be called in order to deliver the -SIGINT signal. This allows Tramp to send the SIGINT signal to remote -asynchronous processes. The hitherto existing implementation has been -moved to 'internal-default-interrupt-process'. - -+++ -** The new function 'read-multiple-choice' prompts for multiple-choice -questions, with a handy way to display help texts. - ---- -** 'comment-indent-function' values may now return a cons to specify a -range of indentation. - -+++ -** New optional argument TEXT in 'make-temp-file'. - ---- -** New function `define-symbol-prop'. - -** Checksum/Hash - -+++ -** New function 'secure-hash-algorithms' to list the algorithms that -'secure-hash' supports. -See the node "(elisp) Checksum/Hash" in the ELisp manual for details. - -+++ -** Emacs now exposes the GnuTLS cryptographic API with the functions -'gnutls-macs' and 'gnutls-hash-mac'; 'gnutls-digests' and -'gnutls-hash-digest'; 'gnutls-ciphers' and 'gnutls-symmetric-encrypt' -and 'gnutls-symmetric-decrypt'. -See the node "(elisp) GnuTLS Cryptography" in the ELisp manual for details. - -+++ -** Emacs now supports records for user-defined types, via the new -functions 'make-record', 'record', and 'recordp'. Records are now -used internally to represent cl-defstruct and defclass instances, for -example. - -+++ -** 'save-some-buffers' now uses 'save-some-buffers-default-predicate' -to decide which buffers to ask about, if the PRED argument is nil. -The default value of 'save-some-buffers-default-predicate' is nil, -which means ask about all file-visiting buffers. - ---- -** string-(to|as|make)-(uni|multi)byte are now declared obsolete. - -+++ -** New variable 'while-no-input-ignore-events' which allow -setting which special events 'while-no-input' should ignore. -It is a list of symbols. - ---- -** New function 'undo-amalgamate-change-group' to get rid of -undo-boundaries between two states. - ---- -** New var 'definition-prefixes' is a hash table mapping prefixes to -the files where corresponding definitions can be found. This can be -used to fetch definitions that are not yet loaded, for example for -'C-h f'. - ---- -** New var 'syntax-ppss-table' to control the syntax-table used in -'syntax-ppss'. - -+++ -** 'define-derived-mode' can now specify an :after-hook form, which -gets evaluated after the new mode's hook has run. This can be used to -incorporate configuration changes made in the mode hook into the -mode's setup. - ---- -** Autoload files can be generated without timestamps, -by setting 'autoload-timestamps' to nil. -FIXME As an experiment, nil is the current default. -If no insurmountable problems before next release, it can stay that way. - ---- -** 'gnutls-boot' now takes a parameter ':complete-negotiation' that -says that negotiation should complete even on non-blocking sockets. - ---- -** There is now a new variable 'flyspell-sort-corrections-function' -that allows changing the way corrections are sorted. - ---- -** The new command 'fortune-message' has been added, which displays -fortunes in the echo area. - -+++ -** New function 'func-arity' returns information about the argument list -of an arbitrary function. This generalizes 'subr-arity' for functions -that are not built-in primitives. We recommend using this new -function instead of 'subr-arity'. - ---- -** New function 'region-bounds' can be used in the interactive spec -to provide region boundaries (for rectangular regions more than one) -to an interactively callable function as a single argument instead of -two separate arguments region-beginning and region-end. - -+++ -** 'parse-partial-sexp' state has a new element. Element 10 is -non-nil when the last character scanned might be the first character -of a two character construct, i.e., a comment delimiter or escaped -character. Its value is the syntax of that last character. - -+++ -** 'parse-partial-sexp's state, element 9, has now been confirmed as -permanent and documented, and may be used by Lisp programs. Its value -is a list of currently open parenthesis positions, starting with the -outermost parenthesis. - ---- -** 'read-color' will now display the color names using the color itself -as the background color. - ---- -** The function 'redirect-debugging-output' now works on platforms -other than GNU/Linux. - -+++ -** The new function 'string-version-lessp' compares strings by -interpreting consecutive runs of numerical characters as numbers, and -compares their numerical values. According to this predicate, -"foo2.png" is smaller than "foo12.png". - ---- -** Numeric comparisons and 'logb' no longer return incorrect answers -due to internal rounding errors. For example, (< most-positive-fixnum -(+ 1.0 most-positive-fixnum)) now correctly returns t on 64-bit hosts. - ---- -** The functions 'ffloor', 'fceiling', 'ftruncate' and 'fround' now -accept only floating-point arguments, as per their documentation. -Formerly, they quietly accepted integer arguments and sometimes -returned nonsensical answers, e.g., (< N (ffloor N)) could return t. - ---- -** On hosts like GNU/Linux x86-64 where a 'long double' fraction -contains at least EMACS_INT_WIDTH - 3 bits, 'format' no longer returns -incorrect answers due to internal rounding errors when formatting -Emacs integers with %e, %f, or %g conversions. For example, on these -hosts (eql N (string-to-number (format "%.0f" N))) now returns t for -all Emacs integers N. - ---- -** Calls that accept floating-point integers (for use on hosts with -limited integer range) now signal an error if arguments are not -integral. For example (decode-char 'ascii 0.5) now signals an error. - -+++ -** The new function 'char-from-name' converts a Unicode name string -to the corresponding character code. - -+++ -** New functions 'sxhash-eq' and 'sxhash-eql' return hash codes of a -Lisp object suitable for use with 'eq' and 'eql' correspondingly. If -two objects are 'eq' ('eql'), then the result of 'sxhash-eq' -('sxhash-eql') on them will be the same. - -+++ -** Function 'sxhash' has been renamed to 'sxhash-equal' for -consistency with the new functions. For compatibility, 'sxhash' -remains as an alias to 'sxhash-equal'. - -+++ -** 'make-hash-table' now defaults to a rehash threshold of 0.8125 -instead of 0.8, to avoid rounding glitches. - -+++ -** New function 'add-variable-watcher' can be used to call a function -when a symbol's value is changed. This is used to implement the new -debugger command 'debug-on-variable-change'. - -+++ -** Time conversion functions that accept a time zone rule argument now -allow it to be OFFSET or a list (OFFSET ABBR), where the integer -OFFSET is a count of seconds east of Universal Time, and the string -ABBR is a time zone abbreviation. The affected functions are -'current-time-string', 'current-time-zone', 'decode-time', -'format-time-string', and 'set-time-zone-rule'. - -+++ -** 'format-time-string' now formats "%q" to the calendar quarter. - -+++ -** New built-in function 'mapcan'. -It avoids unnecessary consing (and garbage collection). - -+++ -** 'car' and 'cdr' compositions 'cXXXr' and 'cXXXXr' are now part of Elisp. - -+++ -** 'gensym' is now part of Elisp. - ---- -** Low-level list functions like 'length' and 'member' now do a better -job of signaling list cycles instead of looping indefinitely. - -+++ -** The new functions 'make-nearby-temp-file' and 'temporary-file-directory' -can be used for creation of temporary files of remote or mounted directories. - -+++ -** On GNU platforms when operating on a local file, 'file-attributes' -no longer suffers from a race when called while another process is -altering the filesystem. On non-GNU platforms 'file-attributes' -attempts to detect the race, and returns nil if it does so. - -+++ -** The new function 'file-local-name' can be used to specify arguments -of remote processes. - -+++ -** The new functions 'file-name-quote', 'file-name-unquote' and -'file-name-quoted-p' can be used to quote / unquote file names with -the prefix "/:". - -+++ -** The new error 'file-missing', a subcategory of 'file-error', is now -signaled instead of 'file-error' if a file operation acts on a file -that does not exist. - -+++ -** The function 'delete-directory' no longer signals an error when -operating recursively and when some other process deletes the directory -or its files before 'delete-directory' gets to them. - -+++ -*** New error type 'user-search-failed' like 'search-failed' but -avoids debugger like 'user-error'. - -+++ -** The function 'line-number-at-pos' now takes a second optional -argument 'absolute'. If this parameter is nil, the default, this -function keeps on returning the line number taking potential narrowing -into account. If this parameter is non-nil, the function ignores -narrowing and returns the absolute line number. - ---- -** The function 'color-distance' now takes a second optional argument -'metric'. When non-nil, it should be a function of two arguments that -accepts two colors and returns a number. - -** Changes in Frame and Window Handling - -+++ -*** Resizing a frame no longer runs 'window-configuration-change-hook'. -'window-size-change-functions' should be used instead. - -+++ -*** The new function 'frame-size-changed-p' can tell whether a frame has -been resized since the last time 'window-size-change-functions' has been -run. - -+++ -*** The function 'frame-geometry' now also returns the width of a -frame's outer border. - -+++ -*** New frame parameters and changed semantics for older ones - -+++ -**** 'z-group' positions a frame above or below all others. - -+++ -**** 'min-width' and 'min-height' specify the absolute minimum size of a -frame. - -+++ -**** 'parent-frame' makes a frame the child frame of another Emacs -frame. The section "Child Frames" in the Elisp manual describes the -intrinsics of that relationship. - -+++ -**** 'delete-before' triggers deletion of one frame before that of -another. - -+++ -**** 'mouse-wheel-frame' specifies another frame whose windows shall be -scrolled instead. - -+++ -**** 'no-other-frame' has 'next-frame' and 'previous-frame' skip this -frame. - -+++ -**** 'skip-taskbar' removes a frame's icon from the taskbar and has -Alt-<TAB> skip this frame. - -+++ -**** 'no-focus-on-map' avoids that a frame gets input focus when mapped. - -+++ -**** 'no-accept-focus' means that a frame does not want to get input -focus via the mouse. - -+++ -**** 'undecorated' removes the window manager decorations from a frame. - -+++ -**** 'override-redirect' tells the window manager to disregard this -frame. - -+++ -**** 'width' and 'height' allow to specify pixel values and ratios now. - -+++ -**** 'left' and 'top' allow to specify ratios now. - -+++ -**** 'keep-ratio' preserves size and position of child frames when their -parent frame is resized. - -+++ -**** 'no-special-glyphs' suppresses display of truncation and -continuation glyphs in a frame. - -+++ -**** 'auto-hide-function' and 'minibuffer-exit' handle auto hiding of -frames and exiting from minibuffer individually. - -+++ -**** 'fit-frame-to-buffer-margins' and 'fit-frame-to-buffer-sizes' -handle fitting a frame to its buffer individually. - -+++ -**** 'drag-internal-border', 'drag-with-header-line', -'drag-with-mode-line', 'snap-width', 'top-visible' and 'bottom-visible' -allow to drag and resize frames with the mouse. - -*** The new function 'frame-list-z-order' returns a list of all frames -in Z (stacking) order. - -+++ -*** The function 'x-focus-frame' optionally tries to not activate its -frame. - -+++ -*** The variable 'focus-follows-mouse' has a third meaningful value -'auto-raise' to indicate that the window manager automatically raises a -frame when the mouse pointer enters it. - -+++ -*** The new function 'frame-restack' puts a frame above or below -another on the display. - -+++ -*** The new face 'internal-border' specifies the background of a frame's -internal border. - -+++ -*** The NORECORD argument of 'select-window' now has a meaningful value -'mark-for-redisplay' which is like any other non-nil value but marks -WINDOW for redisplay. - -+++ -*** Support for side windows is now official. -The display action function 'display-buffer-in-side-window' will -display its buffer in a side window. Functions for toggling all side -windows on a frame, changing and reversing the layout of side windows -and returning the main (major non-side) window of a frame are -provided. For details consult the section "Side Windows" in the Elisp -manual. - -+++ -*** Support for atomic windows - rectangular compositions of windows -treated by 'split-window', 'delete-window' and 'delete-other-windows' -like a single live window - is now official. For details consult the -section "Atomic Windows" in the Elisp manual. - -+++ -*** New 'display-buffer' alist entry 'window-parameters' allows to -assign window parameters to the window used for displaying the buffer. - -+++ -*** New function 'display-buffer-reuse-mode-window' is an action function -suitable for use in 'display-buffer-alist'. For example, to avoid -creating a new window when opening man pages when there's already one, -use - -(add-to-list 'display-buffer-alist - '("\\`\\*Man .*\\*\\'" . - (display-buffer-reuse-mode-window - (inhibit-same-window . nil) - (mode . Man-mode)))) - -+++ -*** New window parameter 'no-delete-other-windows' prevents that -its window gets deleted by 'delete-other-windows'. - -+++ -*** New window parameters 'mode-line-format' and 'header-line-format' -allow to override the buffer-local formats for this window. - -+++ -*** New command 'window-swap-states' swaps the states of two live -windows. - -+++ -*** New functions 'window-pixel-width-before-size-change' and -'window-pixel-height-before-size-change' support detecting which -window changed size when 'window-size-change-functions' are run. - -+++ -*** The new function 'window-lines-pixel-dimensions' returns the pixel -dimensions of a window's text lines. - -+++ -*** The new function 'window-largest-empty-rectangle' returns the -dimensions of the largest rectangular area not occupying any text in a -window's body. - -+++ -*** The semantics of 'mouse-autoselect-window' has changed slightly. -For details see the section "Mouse Window Auto-selection" in the Elisp -manual. - ---- -** 'tcl-auto-fill-mode' is now declared obsolete. Its functionality -can be replicated simply by setting 'comment-auto-fill-only-comments'. - -** New pcase pattern 'rx' to match against a rx-style regular expression. -For details, see the doc string of 'rx--pcase-macroexpander'. - ---- -** New functions to set region from secondary selection and vice versa. -The new functions 'secondary-selection-to-region' and -'secondary-selection-from-region' let you set the beginning and the -end of the region from those of the secondary selection and vise -versa. +* Lisp Changes in Emacs 27.1 -* Changes in Emacs 26.1 on Non-Free Operating Systems - -+++ -** Intercepting hotkeys on Windows 7 and later now works better. -The new keyboard hooking code properly grabs system hotkeys such as -Win-* and Alt-TAB, in a way that Emacs can get at them before the -system. This makes the 'w32-register-hot-key' functionality work -again on all versions of MS-Windows starting with Windows 7. On -Windows NT and later you can now register any hotkey combination. (On -Windows 9X, the previous limitations, spelled out in the Emacs manual, -still apply.) - ---- -** 'convert-standard-filename' no longer mirrors slashes on MS-Windows. -Previously, on MS-Windows this function converted slash characters in -file names into backslashes. It no longer does that. If your Lisp -program used 'convert-standard-filename' to prepare file names to be -passed to subprocesses (which is not the recommended usage of that -function), you will now have to mirror slashes in your application -code. One possible way is this: - - (let ((start 0)) - (while (string-match "/" file-name start) - (aset file-name (match-beginning 0) ?\\) - (setq start (match-end 0)))) - ---- -** GUI sessions on MS-Windows now treat SIGINT like Posix platforms do. -The effect of delivering a Ctrl-C (SIGINT) signal to a GUI Emacs on -MS-Windows is now the same as on Posix platforms -- Emacs saves the -session and exits. In particular, this will happen if you start -emacs.exe from the Windows shell, then type Ctrl-C into that shell's -window. - ---- -** 'signal-process' supports SIGTRAP on Windows XP and later. -The 'kill' emulation on Windows now maps SIGTRAP to a call to the -'DebugBreakProcess' API. This causes the receiving process to break -execution and return control to the debugger. If no debugger is -attached to the receiving process, the call is typically ignored. -This is in contrast to the default action on POSIX Systems, where it -causes the receiving process to terminate with a core dump if no -debugger has been attached to it. - ---- -** 'set-mouse-position' and 'set-mouse-absolute-pixel-position' work -on macOS. - ---- -** Emacs can now be run as a GUI application from the command line on -macOS. - -+++ -** 'ns-appearance' and 'ns-transparent-titlebar' change the appearance -of frame decorations on macOS 10.9+. - ---- -** 'ns-use-thin-smoothing' enables thin font smoothing on macOS 10.8+. - ---- -** 'process-attributes' on Darwin systems now returns more information. - ---- -** Mousewheel and trackpad scrolling on macOS 10.7+ now behaves more -like the macOS default. The new variables 'ns-mwheel-line-height', -'ns-use-mwheel-acceleration' and 'ns-use-mwheel-momentum' can be used -to customize the behavior. +* Changes in Emacs 27.1 on Non-Free Operating Systems ---------------------------------------------------------------------- diff --git a/etc/NEWS.26 b/etc/NEWS.26 new file mode 100644 index 00000000000..b734e8dd19c --- /dev/null +++ b/etc/NEWS.26 @@ -0,0 +1,1936 @@ +GNU Emacs NEWS -- history of user-visible changes. + +Copyright (C) 2014-2017 Free Software Foundation, Inc. +See the end of the file for license conditions. + +Please send Emacs bug reports to bug-gnu-emacs@gnu.org. +If possible, use M-x report-emacs-bug. + +This file is about changes in Emacs version 26. + +See file HISTORY for a list of GNU Emacs versions and release dates. +See files NEWS.25, NEWS.24, NEWS.23, NEWS.22, NEWS.21, NEWS.20, +NEWS.19, NEWS.18, and NEWS.1-17 for changes in older Emacs versions. + +You can narrow news to a specific version by calling 'view-emacs-news' +with a prefix argument or by typing C-u C-h C-n. + +Temporary note: ++++ indicates that all necessary documentation updates are complete. + (This means all relevant manuals in doc/ AND lisp doc-strings.) +--- means no change in the manuals is needed. +When you add a new item, use the appropriate mark if you are sure it applies, + + +* Installation Changes in Emacs 26.1 + +** By default libgnutls is now required when building Emacs. +Use 'configure --with-gnutls=no' to build even when GnuTLS is missing. + +** GnuTLS version 2.12.2 or later is now required, instead of merely +version 2.6.6 or later. + +** The new option 'configure --with-mailutils' causes Emacs to rely on +GNU Mailutils to retrieve email. It is recommended, and is the +default if GNU Mailutils is installed. When --with-mailutils is not +in effect, the Emacs build procedure by default continues to build and +install a limited 'movemail' substitute that retrieves POP3 email only +via insecure channels; to avoid this problem, use either +--with-mailutils or --without-pop when configuring. + +** The new option 'configure --enable-gcc-warnings=warn-only' causes +GCC to issue warnings without stopping the build. This behavior is +now the default in developer builds. As before, use +'--disable-gcc-warnings' to suppress GCC's warnings, and +'--enable-gcc-warnings' to stop the build if GCC issues warnings. + +** When GCC warnings are enabled, '--enable-check-lisp-object-type' is +now enabled by default when configuring. + ++++ +** The Emacs server now has socket-launching support. This allows +socket based activation, where an external process like systemd can +invoke the Emacs server process upon a socket connection event and +hand the socket over to Emacs. Emacs uses this socket to service +emacsclient commands. This new functionality can be disabled with the +configure option '--disable-libsystemd'. + ++++ +** A systemd user unit file is provided. Use it in the standard way: +systemctl --user enable emacs +(If your Emacs is installed in a non-standard location, you may +need to copy the emacs.service file to eg ~/.config/systemd/user/) + +** New configure option '--disable-build-details' attempts to build an +Emacs that is more likely to be reproducible; that is, if you build +and install Emacs twice, the second Emacs is a copy of the first. +Deterministic builds omit the build date from the output of the +'emacs-version' and 'erc-cmd-SV' functions, and the leave the +following variables nil: 'emacs-build-system', 'emacs-build-time', +'erc-emacs-build-time'. + +--- +** Emacs can now be built with support for Little CMS. + +If the lcms2 library is installed, Emacs will enable features built on +top of that library. The new configure option '--without-lcms2' can +be used to build without lcms2 support even if it is installed. Emacs +linked to Little CMS exposes color management functions in Lisp: the +color metrics 'lcms-cie-de2000' and 'lcms-cam02-ucs', as well as +functions for conversion to and from CIE CAM02 and CAM02-UCS. + +** The configure option '--with-gameuser' now defaults to 'no', +as this appears to be the most common configuration in practice. +When it is 'no', the shared game directory and the auxiliary program +update-game-score are no longer needed and are not installed. + +** Emacs no longer works on IRIX. We expect that Emacs users are not +affected by this, as SGI stopped supporting IRIX in December 2013. + + +* Startup Changes in Emacs 26.1 + ++++ +** New option '--fg-daemon'. This is the same as '--daemon', except +it runs in the foreground and does not fork. This is intended for +modern init systems such as systemd, which manage many of the traditional +aspects of daemon behavior themselves. '--bg-daemon' is now an alias +for '--daemon'. + ++++ +** New option '--module-assertions'. +When given this option, Emacs will perform expensive correctness +checks when dealing with dynamic modules. This is intended for module +authors that wish to verify that their module conforms to the module +requirements. The option makes Emacs abort if a module-related +assertion triggers. + ++++ +** Emacs now supports 24-bit colors on capable text terminals +Terminal is automatically initialized to use 24-bit colors if the +required capabilities are found in terminfo. See the FAQ node +"Colors on a TTY" for more information. + ++++ +** Emacs now obeys the X resource "scrollBar" at startup. +The effect is similar to that of "toolBar" resource on the tool bar. + + +* Changes in Emacs 26.1 + ++++ +** Option 'buffer-offer-save' can be set to new value, 'always'. When + set to 'always', the command `save-some-buffers' will always offer + this buffer for saving. + +** Security vulnerability related to Enriched Text mode is removed. + ++++ +*** Enriched Text mode does not evaluate Lisp in 'display' properties. +This feature allows saving 'display' properties as part of text. +Emacs 'display' properties support evaluation of arbitrary Lisp forms +as part of processing the property for display, so displaying Enriched +Text could be vulnerable to executing arbitrary malicious Lisp code +included in the text (e.g., sent as part of an email message). +Therefore, execution of arbitrary Lisp forms in 'display' properties +decoded by Enriched Text mode is now disabled by default. Customize +the new option 'enriched-allow-eval-in-display-props' to a non-nil +value to allow Lisp evaluation in decoded 'display' properties. + +This vulnerability was introduced in Emacs 21.1. To work around that +in Emacs versions before 25.3, append the following to your ~/.emacs +init file: + + (eval-after-load "enriched" + '(defun enriched-decode-display-prop (start end &optional param) + (list start end))) + ++++ +** Functions in 'write-contents-functions' can fully short-circuit the +'save-buffer' process. Previously, saving a buffer that was not +visiting a file would always prompt for a file name. Now it only does +so if 'write-contents-functions' is nil (or all its functions return +nil). + +--- +** New variable 'executable-prefix-env' for inserting magic signatures. +This variable affects the format of the interpreter magic number +inserted by 'executable-set-magic'. If non-nil, the magic number now +takes the form "#!/usr/bin/env interpreter", otherwise the value +determined by 'executable-prefix', which is by default +"#!/path/to/interpreter". By default, 'executable-prefix-env' is nil, +so the default behavior is not changed. + ++++ +** The variable 'emacs-version' no longer includes the build number. +This is now stored separately in a new variable, 'emacs-build-number'. + ++++ +** Emacs now provides a limited form of concurrency with Lisp threads. +Concurrency in Emacs Lisp is "mostly cooperative", meaning that +Emacs will only switch execution between threads at well-defined +times: when Emacs waits for input, during blocking operations related +to threads (such as mutex locking), or when the current thread +explicitly yields. Global variables are shared among all threads, but +a 'let' binding is thread-local. Each thread also has its own current +buffer and its own match data. + +See the chapter "Threads" in the ELisp manual for full documentation +of these facilities. + ++++ +** The new user variable 'electric-quote-chars' provides a list +of curved quotes for 'electric-quote-mode', allowing user to choose +the types of quotes to be used. + +--- +** The new user option 'electric-quote-context-sensitive' makes +'electric-quote-mode' context sensitive. If it is non-nil, you can +type an ASCII apostrophe to insert an opening or closing quote, +depending on context. Emacs will replace the apostrophe by an opening +quote character at the beginning of the buffer, the beginning of a +line, after a whitespace character, and after an opening parenthesis; +and it will replace the apostrophe by a closing quote character in all +other cases. + +--- +** The new variable 'electric-quote-inhibit-functions' controls when +to disable electric quoting based on context. Major modes can add +functions to this list; Emacs will temporarily disable +'electric-quote-mode' whenever any of the functions returns non-nil. +This can be used by major modes that derive from 'text-mode' but allow +inline code segments, such as 'markdown-mode'. + ++++ +** The new user variable 'dired-omit-case-fold' allows the user to +customize the case-sensitivity of dired-omit-mode. It defaults to +the same sensitivity as that of the filesystem for the corresponding +dired buffer. + ++++ +** Emacs now uses double buffering to reduce flicker when editing and +resizing graphical Emacs frames on the X Window System. This support +requires the DOUBLE-BUFFER extension, which major X servers have +supported for many years. If your system has this extension, but an +Emacs built with double buffering misbehaves on some displays you use, +you can disable the feature by adding + + '(inhibit-double-buffering . t) + +to default-frame-alist. Or inject this parameter into the selected +frame by evaluating this form: + + (modify-frame-parameters nil '((inhibit-double-buffering . t))) + +--- +The group 'wp', whose label was "text", is now deprecated. +Use the new group 'text', which inherits from 'wp', instead. + ++++ +** The new function 'call-shell-region' executes a command in an +inferior shell with the buffer region as input. + ++++ +** The new user option 'shell-command-dont-erase-buffer' controls +if the output buffer is erased between shell commands; if non-nil, +the output buffer is not erased; this variable also controls where +to set the point in the output buffer: beginning of the output, +end of the buffer or save the point. +When 'shell-command-dont-erase-buffer' is nil, the default value, +the behavior of 'shell-command', 'shell-command-on-region' and +'async-shell-command' is as usual. + ++++ +** The new user option 'async-shell-command-display-buffer' controls +whether the output buffer of an asynchronous command is shown +immediately, or only when there is output. + ++++ +** The new user option 'mouse-select-region-move-to-beginning' +controls the position of point when double-clicking mouse-1 on the end +of a parenthetical grouping or string-delimiter: the default value nil +keeps point at the end of the region, setting it to non-nil moves +point to the beginning of the region. + ++++ +** The new user option 'mouse-drag-and-drop-region' allows to drag the +entire region of text to another place or another buffer. + ++++ +** The new user option 'confirm-kill-processes' allows the user to +skip a confirmation prompt for killing subprocesses when exiting +Emacs. When set to t (the default), Emacs will prompt for +confirmation before killing subprocesses on exit, which is the same +behavior as before. + +--- +** 'find-library-name' will now fall back on looking at 'load-history' +to try to locate libraries that have been loaded with an explicit path +outside 'load-path'. + ++++ +** Faces in 'minibuffer-prompt-properties' no longer overwrite properties +in the text in functions like 'read-from-minibuffer', but instead are +added to the end of the face list. This allows users to say things +like '(read-from-minibuffer (propertize "Enter something: " 'face 'bold))'. + ++++ +** The new variable 'extended-command-suggest-shorter' has been added +to control whether to suggest shorter 'M-x' commands or not. + +--- +** icomplete now respects 'completion-ignored-extensions'. + ++++ +** Non-breaking hyphens are now displayed with the 'nobreak-hyphen' +face instead of the 'escape-glyph' face. + ++++ +** Approximations to quotes are now displayed with the new 'homoglyph' +face instead of the 'escape-glyph' face. + ++++ +** New face 'header-line-highlight'. +This face is the header-line analogue of 'mode-line-highlight'; it +should be the preferred mouse-face for mouse-sensitive elements in the +header line. + +--- +** 'C-x h' ('mark-whole-buffer') will now avoid marking the prompt +part of minibuffers. + +--- +** 'fill-paragraph' no longer marks the buffer as changed unless it +actually changed something. + +--- +** The locale language name 'ca' is now mapped to the language +environment 'Catalan', which has been added. + +--- +** 'align-regexp' has a separate history for its interactive argument. +'align-regexp' no longer shares its history with all other +history-less functions that use 'read-string'. + ++++ +** The networking code has been reworked so that it's more +asynchronous than it was (when specifying :nowait t in +'make-network-process'). How asynchronous it is varies based on the +capabilities of the system, but on a typical GNU/Linux system the DNS +resolution, the connection, and (for TLS streams) the TLS negotiation +are all done without blocking the main Emacs thread. To get +asynchronous TLS, the TLS boot parameters have to be passed in (see +the manual for details). + +Certain process oriented functions (like 'process-datagram-address') +will block until socket setup has been performed. The recommended way +to deal with asynchronous sockets is to avoid interacting with them +until they have changed status to "run". This is most easily done +from a process sentinel. + +--- +** 'make-network-process' and 'open-network-stream' sometimes allowed +:service to be an integer string (e.g., :service "993") and sometimes +required an integer (e.g., :service 993). This difference has been +eliminated, and integer strings work everywhere. + +--- +** It is possible to disable attempted recovery on fatal signals. +Two new variables support disabling attempts to recover from stack +overflow and to avoid automatic auto-save when Emacs is delivered a +fatal signal. 'attempt-stack-overflow-recovery', if set to 'nil', +will disable attempts to recover from C stack overflows; Emacs will +then crash as with any other fatal signal. +'attempt-orderly-shutdown-on-fatal-signal', if set to 'nil', will +disable attempts to auto-save the session and shut down in an orderly +fashion when Emacs receives a fatal signal; instead, Emacs will +terminate immediately. Both variables are non-'nil' by default. +These variables are for users who would like to avoid the small +probability of data corruption due to techniques Emacs uses to recover +in these situations. + ++++ +** File local and directory local variables are now initialized each +time the major mode is set, not just when the file is first visited. +These local variables will thus not vanish on setting a major mode. + ++++ +** A second dir-local file (.dir-locals-2.el) is now accepted. +See the variable 'dir-locals-file-2' for more information. + ++++ +** Connection-local variables can be used to specify local variables +with a value depending on the connected remote server. For details, +see the node "Connection Local Variables" in the ELisp manual. + +--- +** International domain names (IDNA) are now encoded via the new +puny.el library, so that one can visit Web sites with non-ASCII URLs. + ++++ +** The new 'list-timers' command lists all active timers in a buffer, +where you can cancel them with the 'c' command. + ++++ +** 'switch-to-buffer-preserve-window-point' now defaults to t. + ++++ +** The new variable 'debugger-stack-frame-as-list' allows displaying +all call stack frames in a Lisp backtrace buffer as lists. Both +debug.el and edebug.el have been updated to heed to this variable. + +--- +** Values in call stack frames are now displayed using 'cl-prin1'. +The old behaviour of using 'prin1' can be restored by customizing the +new option 'debugger-print-function'. + ++++ +** NUL bytes in text copied to the system clipboard are now replaced with "\0". + ++++ +** The new variable 'x-ctrl-keysym' has been added to the existing +roster of X keysyms. It can be used in combination with another +variable of this kind to swap modifiers in Emacs. + +--- +** New input methods: 'cyrillic-tuvan', 'polish-prefix'. + +--- +** The 'dutch' input method no longer attempts to support Turkish too. +Also, it no longer converts 'IJ' and 'ij' to the compatibility +characters U+0132 LATIN CAPITAL LIGATURE IJ and U+0133 LATIN SMALL +LIGATURE IJ. + ++++ +** File name quoting by adding the prefix "/:" is now possible for the +local part of a remote file name. Thus, if you have a directory named +"/~" on the remote host "foo", you can prevent it from being +substituted by a home directory by writing it as "/foo:/:/~/file". + ++++ +** The new variable 'maximum-scroll-margin' allows having effective +settings of 'scroll-margin' up to half the window size, instead of +always restricting the margin to a quarter of the window. + ++++ +** Emacs can scroll horizontally using mouse, touchpad, and trackbar. +You can enable this by customizing 'mwheel-tilt-scroll-p'. If you +want to reverse the direction of the scroll, customize +'mwheel-flip-direction'. + ++++ +** Emacsclient has a new option -u/--suppress-output. +This option suppresses display of return values from the server +process. + ++++ +** Emacsclient has a new option -T/--tramp. +This helps with using a local Emacs session as the server for a remote +emacsclient. With appropriate setup, one can now set the EDITOR +environment variable on a remote machine to emacsclient, and +use the local Emacs to edit remote files via Tramp. See the node +"emacsclient Options" in the user manual for the details. + +--- +** New user option 'dig-program-options' and extended functionality +for DNS-querying functions 'nslookup-host', 'dns-lookup-host', +and 'run-dig'. Each function now accepts an optional name server +argument interactively (with a prefix argument) and non-interactively. + ++++ +** 'describe-key-briefly' now ignores mouse movement events. + ++++ +** The new variable 'eval-expression-print-maximum-character' prevents +large integers from being displayed as characters by 'M-:' and similar +commands. + +--- +** Two new commands for finding the source code of Emacs Lisp +libraries: 'find-library-other-window' and 'find-library-other-frame'. + ++++ +** The new variable 'display-raw-bytes-as-hex' allows to change the +display of raw bytes from octal to hex. + ++++ +** You can now provide explicit field numbers in format specifiers. +For example, '(format "%2$s %1$s" "X" "Y")' produces "Y X". + ++++ +** Emacs now supports optional display of line numbers in the buffer. +This is similar to what linum-mode provides, but much faster and +doesn't usurp the display margin for the line numbers. Customize the +buffer-local variable 'display-line-numbers' to activate this optional +display. Alternatively, you can use the `display-line-numbers-mode' +minor mode or the global `global-display-line-numbers-mode'. When +using these modes, customize `display-line-numbers-type' with the same +value as you would use with `display-line-numbers'. + +Line numbers are not displayed at all in minibuffer windows and in +tooltips, as they are not useful there. + +Lisp programs can disable line-number display for a particular screen +line by putting the 'display-line-numbers-disable' text property or +overlay property on the first character of that screen line. This is +intended for add-on packages that need a finer control of the display. + +Lisp programs that need to know how much screen estate is used up for +line-number display in a window can use the new function +'line-number-display-width'. + +Linum mode and all similar packages are henceforth becoming obsolete. +Users and developers are encouraged to switch to this new feature +instead. + ++++ +** emacsclient now accepts command-line options in ALTERNATE_EDITOR +and --alternate-editor. For example, ALTERNATE_EDITOR="emacs -Q -nw". +Arguments may be quoted "like this", so that for example an absolute +path containing a space may be specified; quote escaping is not +supported. + + +* Editing Changes in Emacs 26.1 + ++++ +** New variable 'column-number-indicator-zero-based'. +Traditionally, in Column Number mode, the displayed column number +counts from zero starting at the left margin of the window. This +behavior is now controlled by 'column-number-indicator-zero-based'. +If you would prefer for the displayed column number to count from one, +you may set this variable to nil. (Behind the scenes, there is now a +new mode line construct, '%C', which operates exactly as '%c' does +except that it counts from one.) + ++++ +** New single-line horizontal scrolling mode. +The 'auto-hscroll-mode' variable can now have a new special value, +'current-line', which causes only the line where the cursor is +displayed to be horizontally scrolled when lines are truncated on +display and point moves outside the left or right window margin. + ++++ +** New mode line constructs '%o' and '%q', and user option +'mode-line-percent-position'. '%o' displays the "degree of travel" of +the window through the buffer. Unlike the default '%p', this +percentage approaches 100% as the window approaches the end of the +buffer. '%q' displays the percentage offsets of both the start and +the end of the window, e.g. "5-17%". The new option +'mode-line-percent-position' makes it easier to switch between '%p', +'%P', and these new constructs. + ++++ +** Two new user options 'list-matching-lines-jump-to-current-line' and +'list-matching-lines-current-line-face' to show highlighted the current +line in *Occur* buffer. + ++++ +** The 'occur' command can now operate on the region. + ++++ +** New bindings for 'query-replace-map'. +'undo', undo the last replacement; bound to 'u'. +'undo-all', undo all replacements; bound to 'U'. + +--- +** 'delete-trailing-whitespace' deletes whitespace after form feed. +In modes where form feed was treated as a whitespace character, +'delete-trailing-whitespace' would keep lines containing it unchanged. +It now deletes whitespace after the last form feed thus behaving the +same as in modes where the character is not whitespace. + +--- +** Emacs no longer prompts about editing a changed file when the file's +content is unchanged. Instead of only checking the modification time, +Emacs now also checks the file's actual content before prompting the user. + +--- +** Various casing improvements. + +*** 'upcase', 'upcase-region' et al. convert title case characters +(such as Dz) into their upper case form (such as DZ). + +*** 'capitalize', 'upcase-initials' et al. make use of title-case forms +of initial characters (correctly producing for example Džungla instead +of incorrect DŽungla). + +*** Characters which turn into multiple ones when cased are correctly handled. +For example, fi ligature is converted to FI when upper cased. + +*** Greek small sigma is correctly handled when at the end of the word. +Strings such as ΌΣΟΣ are now correctly converted to Όσος when +capitalized instead of incorrect Όσοσ (compare lowercase sigma at the +end of the word). + ++++ +** Emacs can now auto-save buffers to visited files in a more robust +manner via the new mode 'auto-save-visited-mode'. Unlike +'auto-save-visited-file-name', this mode uses the normal saving +procedure and therefore obeys saving hooks. +'auto-save-visited-file-name' is now obsolete. + ++++ +** New behavior of 'mark-defun'. +Prefix argument selects that many (or that many more) defuns. +Negative prefix arg flips the direction of selection. Also, +'mark-defun' between defuns correctly selects N following defuns (or +-N previous for negative arguments). Finally, comments preceding the +defun are selected unless they are separated from the defun by a blank +line. + +** New command 'replace-buffer-contents'. +This command replaces the contents of the accessible portion of the +current buffer with the contents of the accessible portion of a +different buffer while keeping point, mark, markers, and text +properties as intact as possible. + ++++ +** New commands 'apropos-local-variable' and 'apropos-local-value. +These are buffer-local versions of 'apropos-variable' and +'apropos-value', respectively. They show buffer-local variables whose +names and values, respectively, match a given pattern. + ++++ +** More user control of reordering bidirectional text for display. +The two new variables, 'bidi-paragraph-start-re' and +'bidi-paragraph-separate-re', allow customization of what exactly are +paragraphs, for the purposes of bidirectional display. + +--- +** New variable 'x-wait-for-event-timeout'. +This controls how long Emacs will wait for updates to the graphical +state to take effect (making a frame visible, for example). + + +* Changes in Specialized Modes and Packages in Emacs 26.1 + +--- +** New function `cl-generic-p'. + +** Dired + ++++ +*** You can answer 'all' in 'dired-do-delete' to delete recursively all +remaining directories without more prompts. + ++++ +*** Dired supports wildcards in the directory part of the file names. + ++++ +*** You can now use '`?`' in 'dired-do-shell-command'. +It gets replaced by the current file name, like ' ? '. + ++++ +*** A new option 'dired-always-read-filesystem' default to nil. +If non-nil, buffers visiting files are reverted before search them; +for instance, in 'dired-mark-files-containing-regexp' a non-nil value +of this option means the file is revisited in a temporary buffer; +this temporary buffer is the actual buffer searched: the original buffer +visiting the file is not modified. + +--- +*** Users can now customize mouse clicks in Dired in a more flexible way. +The new command 'dired-mouse-find-file' can be bound to a mouse click +and used to visit files/directories in Dired in the selected window. +The new command 'dired-mouse-find-file-other-frame' similarly visits +files/directories in another frame. You can write your own commands +that invoke 'dired-mouse-find-file' with non-default optional +arguments, to tailor the effects of mouse clicks on file names in +Dired buffers. + ++++ +*** In wdired, when editing files to contain slash characters, +the resulting directories are automatically created. Whether to do +this is controlled by the 'wdired-create-parent-directories' variable. + ++++ +*** 'W' is now bound to 'browse-url-of-dired-file', and is useful for +viewing HTML files and the like. + +--- +*** New variable 'dired-clean-confirm-killing-deleted-buffers' +controls whether Dired asks to kill buffers visiting deleted files and +directories. The default is t, so Dired asks for confirmation, to +keep previous behavior. + +--- +** html2text is now marked obsolete. + +--- +** smerge-refine-regions can refine regions in separate buffers + +--- +** Info menu and index completion uses substring completion by default. +This can be customized via the info-menu category in +completion-category-override. + ++++ +** The ancestor buffer is shown by default in 3-way merges. +A new option ediff-show-ancestor and a new toggle +ediff-toggle-show-ancestor. + +--- +** TeX: Add luatex and xetex as alternatives to pdftex + +** Electric-Buffer-menu + ++++ +*** Key 'U' is bound to 'Buffer-menu-unmark-all' and key 'M-DEL' is +bound to 'Buffer-menu-unmark-all-buffers'. + +** bs + +--- +*** Two new commands 'bs-unmark-all', bound to 'U', and +'bs-unmark-previous', bound to <backspace>. + +** Buffer-menu + ++++ +*** Two new commands 'Buffer-menu-unmark-all', bound to 'U' and +'Buffer-menu-unmark-all-buffers', bound to 'M-DEL'. + +--- +** Checkdoc + +*** 'checkdoc-arguments-in-order-flag' now defaults to nil. + +** Gnus + +--- +*** The .newsrc file will now only be saved if the native select +method is an NNTP select method. + ++++ +*** A new command for sorting articles by readedness marks has been +added: 'C-c C-s C-m C-m'. + ++++ + +*** In message-citation-line-format the %Z format is now the time zone name +instead of the numeric form. The %z format continues to be the +numeric form. The new behavior is compatible with format-time-string. + +** Ibuffer + +--- +*** New command 'ibuffer-jump'. + +--- +*** New filter commands 'ibuffer-filter-by-basename', +'ibuffer-filter-by-file-extension', 'ibuffer-filter-by-directory', +'ibuffer-filter-by-starred-name', 'ibuffer-filter-by-modified' +and 'ibuffer-filter-by-visiting-file'; bound respectively +to '/b', '/.', '//', '/*', '/i' and '/v'. + +--- +*** Two new commands 'ibuffer-filter-chosen-by-completion' +and 'ibuffer-and-filter', the second bound to '/&'. + +--- +*** The commands 'ibuffer-pop-filter', 'ibuffer-pop-filter-group', +'ibuffer-or-filter' and 'ibuffer-filter-disable' have the alternative +bindings '/<up>', '/S-<up>', '/|' and '/DEL', respectively. + +--- +*** The data format specifying filters has been extended to allow +explicit logical 'and', and a more flexible form for logical 'not'. +See 'ibuffer-filtering-qualifiers' doc string for full details. + +--- +*** A new command 'ibuffer-copy-buffername-as-kill'; bound +to 'B'. + +--- +*** New command 'ibuffer-change-marks'; bound to '* c'. + +--- +*** A new command 'ibuffer-mark-by-locked' to mark +all locked buffers; bound to '% L'. + +--- +*** A new option 'ibuffer-locked-char' to indicate +locked buffers; Ibuffer shows a new column displaying +'ibuffer-locked-char' for locked buffers. + +--- +*** A new command 'ibuffer-unmark-all-marks' to unmark +all buffers without asking confirmation; bound to +'U'; 'ibuffer-do-replace-regexp' bound to 'r'. + +--- +*** A new command 'ibuffer-mark-by-content-regexp' to mark buffers +whose content matches a regexp; bound to '% g'. + +--- +*** Two new options 'ibuffer-never-search-content-name' and +'ibuffer-never-search-content-mode' used by +'ibuffer-mark-by-content-regexp'. + +** Browse-URL + +--- +*** Support for opening links to man pages in Man or WoMan mode. + +** Comint + +--- +*** New user option 'comint-move-point-for-matching-input' to control +where to place point after C-c M-r and C-c M-s. + +** Compilation mode + +--- +*** Messages from CMake are now recognized. + ++++ +*** The number of errors, warnings, and informational messages is now +displayed in the mode line. These are updated as compilation +proceeds. + +** Grep + +--- +*** Grep commands will now use GNU grep's '--null' option if +available, which allows distinguishing the filename from contents if +they contain colons. This can be controlled by the new custom option +'grep-use-null-filename-separator'. + +--- +*** The grep/rgrep/lgrep functions will now ask about saving files +before running. This is controlled by the 'grep-save-buffers' +variable. + +** Edebug + +--- +*** Edebug can be prevented from pausing 1 second after reaching a +breakpoint (e.g. with "f" and "o") by customizing the new option +'edebug-sit-on-break'. + ++++ +*** New customizable option 'edebug-max-depth' +This allows to enlarge the maximum recursion depth when instrumenting +code. + +** Eshell + +--- +*** 'eshell-input-filter's value is now a named function +'eshell-input-filter-default', and has a new custom option +'eshell-input-filter-initial-space' to ignore adding commands prefixed +with blank space to eshell history. + +** eww + ++++ +*** New 'M-RET' command for opening a link at point in a new eww buffer. + ++++ +*** A new 's' command for switching to another eww buffer via the minibuffer. + +--- +*** The 'o' command ('shr-save-contents') has moved to 'O' to avoid collision +with the 'o' command from 'image-map'. + ++++ +*** A new command 'C' ('eww-toggle-colors') can be used to toggle +whether to use the HTML-specified colors or not. The user can also +customize the 'shr-use-colors' variable. + +--- +*** Images that are being loaded are now marked with gray +"placeholder" images of the size specified by the HTML. They are then +replaced by the real images asynchronously, which will also now +respect width/height HTML specs (unless they specify widths/heights +bigger than the current window). + +--- +*** The 'w' command on links is now 'shr-maybe-probe-and-copy-url'. +'shr-copy-url' now only copies the url at point; users who wish to +avoid accidentally accessing remote links may rebind 'w' and 'u' in +'eww-link-keymap' to it. + + +** Ido + +--- +*** The commands 'find-alternate-file-other-window', +'dired-other-window', 'dired-other-frame', and +'display-buffer-other-window' are now remapped to Ido equivalents if +Ido mode is active. + +** Images + ++++ +*** Images are automatically scaled before displaying based on the +'image-scaling-factor' variable (if Emacs supports scaling the images +in question). + ++++ +*** It's now possible to specify aspect-ratio preserving combinations +of :width/:max-height and :height/:max-width keywords. In either +case, the "max" keywords win. (Previously some combinations would, +depending on the aspect ratio of the image, just be ignored and in +other instances this would lead to the aspect ratio not being +preserved.) + ++++ +*** Images inserted with 'insert-image' and related functions get a +keymap put into the text properties (or overlays) that span the +image. This keymap binds keystrokes for manipulating size and +rotation, as well as saving the image to a file. These commands are +also available in 'image-mode'. + ++++ +*** A new library for creating and manipulating SVG images has been +added. See the "SVG Images" section in the Lisp reference manual for +details. + ++++ +*** New setf-able function to access and set image parameters is +provided: 'image-property'. + +--- +*** New commands 'image-scroll-left' and 'image-scroll-right' +for 'image-mode' that complement 'image-scroll-up' and +'image-scroll-down': they have the same prefix arg behavior and stop +at image boundaries. + +** Image-Dired + +--- +*** Now provides a minor mode 'image-dired-minor-mode' which replaces +the function 'image-dired-setup-dired-keybindings'. + +--- +*** Thumbnail generation is now asynchronous. +The number of concurrent processes is limited by the variable +'image-dired-thumb-job-limit'. + +--- +*** 'image-dired-thumbnail-storage' has a new option 'standard-large' +for generating 256x256 thumbnails according to the Thumbnail Managing +Standard. + +--- +*** Inherits movement keys from 'image-mode' for viewing full images. +This includes the usual char, line, and page movement commands. + +--- +*** All the -options types have been changed to argument lists +instead of shell command strings. This change affects +'image-dired-cmd-create-thumbnail-options', +'image-dired-cmd-create-temp-image-options', +'image-dired-cmd-rotate-thumbnail-options', +'image-dired-cmd-rotate-original-options', +'image-dired-cmd-write-exif-data-options', +'image-dired-cmd-read-exif-data-options', and introduces +'image-dired-cmd-pngnq-options', 'image-dired-cmd-pngcrush-options', +'image-dired-cmd-create-standard-thumbnail-options' + +--- +*** Recognizes more tools by default, including pngnq-s9 and OptiPNG + +--- +*** 'find-file' and related commands now work on thumbnails and +displayed images, providing a default argument of the original file name +via an addition to 'file-name-at-point-functions'. + +--- +** The default 'Info-default-directory-list' no longer checks some obsolete +directory suffixes (gnu, gnu/lib, gnu/lib/emacs, emacs, lib, lib/emacs) +when searching for info directories. + ++++ +** The commands that add ChangeLog entries now prefer a VCS root directory +for the ChangeLog file, if none already exists. Customize +'change-log-directory-files' to nil for the old behavior. + +--- +** Support for non-string values of 'time-stamp-format' has been removed. + +** Message + +--- +*** 'message-use-idna' now defaults to t (because Emacs comes with +built-in IDNA support now). + +--- +*** When sending HTML messages with embedded images, and you have +exiftool installed, and you rotate images with EXIF data (i.e., +JPEGs), the rotational information will be inserted into the outgoing +image in the message. (The original image will not have its +orientation affected.) + +--- +*** The 'message-valid-fqdn-regexp' variable has been removed, since +there are now top-level domains added all the time. Message will no +longer warn about sending emails to top-level domains it hasn't heard +about. + +*** 'message-beginning-of-line' (bound to C-a) understands folded headers. +In 'visual-line-mode' it will look for the true beginning of a header +while in non-'visual-line-mode' it will move the point to the indented +header's value. + +** Package + ++++ +*** The new variable 'package-gnupghome-dir' has been added to control +where the GnuPG home directory (used for signature verification) is +located and whether GnuPG's option "--homedir" is used or not. + +--- +*** Deleting a package no longer respects 'delete-by-moving-to-trash'. + +** Tramp + ++++ +*** The method part of remote file names is mandatory now. +A valid remote file name starts with "/method:host:" or +"/method:user@host:". + ++++ +*** The new pseudo method "-" is a marker for the default method. +"/-::" is the shortest remote file name then. + ++++ +*** The command 'tramp-change-syntax' allows to choose an alternative +remote file name syntax. + ++++ +*** New connection method "sg", which supports editing files under a +different group ID. + ++++ +*** New connection method "doas" for OpenBSD hosts. + ++++ +*** New connection method "gdrive", which allows to access Google +Drive onsite repositories. + ++++ +*** Gateway methods in Tramp have been removed. +Instead, the Tramp manual documents how to configure ssh and PuTTY +accordingly. + ++++ +*** Setting the "ENV" environment variable in +'tramp-remote-process-environment' enables reading of shell +initialization files. + +--- +*** Tramp is able now to send SIGINT to remote asynchronous processes. + +--- +*** Variable 'tramp-completion-mode' is obsoleted. + +--- +** 'auto-revert-use-notify' is set back to t in 'global-auto-revert-mode'. + +** JS mode + +--- +*** JS mode now sets 'comment-multi-line' to t. + +--- +*** New variable 'js-indent-align-list-continuation', when set to nil, +will not align continuations of bracketed lists, but will indent them +by the fixed width 'js-indent-level'. + +** CSS mode + +--- +*** Support for completing attribute values, at-rules, bang-rules, +HTML tags, classes and IDs using the 'completion-at-point' command. +Completion candidates for HTML classes and IDs are retrieved from open +HTML mode buffers. + +--- +*** CSS mode now binds 'C-h S' to a function that will show +information about a CSS construct (an at-rule, property, pseudo-class, +pseudo-element, with the default being guessed from context). By +default the information is looked up on the Mozilla Developer Network, +but this can be customized using 'css-lookup-url-format'. + +--- +*** CSS colors are fontified using the color they represent as the +background. For instance, #ff0000 would be fontified with a red +background. + ++++ +** Emacs now supports character name escape sequences in character and +string literals. The syntax variants \N{character name} and +\N{U+code} are supported. + ++++ +** Prog mode has some support for multi-mode indentation. +This allows better indentation support in modes that support multiple +programming languages in the same buffer, like literate programming +environments or ANTLR programs with embedded Python code. + +A major mode can provide indentation context for a sub-mode through +the 'prog-indentation-context' variable. To support this, modes that +provide indentation should use 'prog-widen' instead of 'widen' and +'prog-first-column' instead of a literal zero. See the node +"Mode-Specific Indent" in the ELisp manual for more details. + +** ERC + +--- +*** New variable 'erc-default-port-tls' used to connect to TLS IRC +servers. + +** URL + ++++ +*** The new function 'url-cookie-delete-cookie' can be used to +programmatically delete all cookies, or cookies from a specific +domain. + ++++ +*** 'url-retrieve-synchronously' now takes an optional timeout parameter. + +--- +*** The URL package now support HTTPS over proxies supporting CONNECT. + ++++ +*** 'url-user-agent' now defaults to 'default', and the User-Agent +string is computed dynamically based on 'url-privacy-level'. + +** VC and related modes + +--- +*** The VC state indicator in the mode line now defaults to more +colorful faces to make it more obvious to the user what the state is. +See the 'vc-faces' customization group. + ++++ +*** 'vc-dir-mode' now binds 'vc-log-outgoing' to 'O'; and has various +branch-related commands on a keymap bound to 'B'. + +--- +*** 'vc-region-history' is now bound to 'C-x v h', replacing the older +'vc-insert-headers' binding. + +** CC mode + +--- +*** Opening a .h file will turn C or C++ mode depending on language used. +This is done with the help of 'c-or-c++-mode' function which analyses +contents of the buffer to determine whether it's a C or C++ source +file. + +--- +** New DNS mode command 'dns-mode-ipv6-to-nibbles' to convert IPv6 addresses +to a format suitable for reverse lookup zone files. + +** Ispell + ++++ +*** Enchant is now supported as a spell-checker. + +Enchant is a meta-spell-checker that uses providers +such as Hunspell to do the actual checking. With it, users can use +spell-checkers not directly supported by Emacs, such as Voikko, Hspell +and AppleSpell, more easily share personal word-lists with other +programs, and configure different spelling-checkers for different +languages. (Version 2.1.0 or later of Enchant is required.) + +** Flymake + ++++ +*** Emacs no longer prompts the user before killing Flymake processes on exit. + + +* New Modes and Packages in Emacs 26.1 + +** New Elisp data-structure library 'radix-tree'. + +** New library 'xdg' with utilities for some XDG standards and specs. + +** HTML + ++++ +*** A new submode of 'html-mode', 'mhtml-mode', is now the default +mode for *.html files. This mode handles indentation, +fontification, and commenting for embedded JavaScript and CSS. + +** New mode 'conf-toml-mode' is a sub-mode of conf-mode, specialized + for editing TOML files. + +** New mode 'conf-desktop-mode' is a sub-mode of conf-unix-mode, +specialized for editing freedesktop.org desktop entries. + +** New minor mode 'pixel-scroll-mode' provides smooth pixel-level scrolling. + +** New major mode 'less-css-mode' (a minor variant of 'css-mode') for +editing Less files. + + +* Incompatible Lisp Changes in Emacs 26.1 + +--- +*** password-data is now a hash-table +so that `password-read' can use any object for the `key' argument. + ++++ +*** Command 'dired-mark-extension' now automatically prepends a '.' to the +extension when not present. The new command 'dired-mark-suffix' behaves +similarly but it doesn't prepend a '.'. + ++++ +** Certain cond/pcase/cl-case forms are now compiled using a faster jump +table implementation. This uses a new bytecode op 'switch', which +isn't compatible with previous Emacs versions. This functionality can +be disabled by setting 'byte-compile-cond-use-jump-table' to nil. + +--- +** The alist 'ucs-names' is now a hash table. + +--- +** 'if-let' and 'when-let' are subsumed by 'if-let*' and 'when-let*'. +The incumbent 'if-let' and 'when-let' are now marked obsolete. +'if-let*' and 'when-let*' do not accept the single tuple special case. +New macro 'and-let*' is an implementation of the Scheme SRFI-2 syntax +of the same name. 'if-let*' and 'when-let*' now accept the same +binding syntax as 'and-let*'. + +--- +** 'C-up', 'C-down', 'C-left' and 'C-right' are now defined in term +mode to send the same escape sequences that xterm does. This makes +things like forward-word in readline work. + +--- +** hideshow mode got four key bindings that are analogous to outline +mode bindings: 'C-c @ C-a', 'C-c @ C-t', 'C-c @ C-d', and 'C-c @ C-e.' + +--- +** Customizable variable 'query-replace-from-to-separator' +now doesn't propertize the string value of the separator. +Instead, text properties are added by query-replace-read-from. +Additionally, the new nil value restores pre-24.5 behavior +of not providing replacement pairs via the history. + +--- +** Some obsolete functions, variables, and faces have been removed: +*** make-variable-frame-local. Variables cannot be frame-local any more. +*** From subr.el: window-dot, set-window-dot, read-input, show-buffer, +eval-current-buffer, string-to-int +*** icomplete-prospects-length. +*** All the default-FOO variables that hold the default value of the +FOO variable. Use 'default-value' and 'setq-default' to access and +change FOO, respectively. The exhaustive list of removed variables is: +'default-mode-line-format', 'default-header-line-format', +'default-line-spacing', 'default-abbrev-mode', 'default-ctl-arrow', +'default-truncate-lines', 'default-left-margin', 'default-tab-width', +'default-case-fold-search', 'default-left-margin-width', +'default-right-margin-width', 'default-left-fringe-width', +'default-right-fringe-width', 'default-fringes-outside-margins', +'default-scroll-bar-width', 'default-vertical-scroll-bar', +'default-indicate-empty-lines', 'default-indicate-buffer-boundaries', +'default-fringe-indicator-alist', 'default-fringe-cursor-alist', +'default-scroll-up-aggressively', 'default-scroll-down-aggressively', +'default-fill-column', 'default-cursor-type', +'default-cursor-in-non-selected-windows', +'default-buffer-file-coding-system', 'default-major-mode', and +'default-enable-multibyte-characters'. +*** Many variables obsoleted in 22.1 referring to face symbols + ++++ +** The variable 'text-quoting-style' is now a customizable option. It +controls whether to and how to translate ASCII quotes in messages and +help output. Its possible values and their semantics remain unchanged +from Emacs 25. In particular, when this variable's value is 'grave', +all quotes in formats are output as-is. + +--- +** Functions like 'check-declare-file' and 'check-declare-directory' +now generate less chatter and more-compact diagnostics. The auxiliary +function 'check-declare-errmsg' has been removed. + ++++ +** The regular expression character class [:blank:] now matches +Unicode horizontal whitespace as defined in the Unicode Technical +Standard #18. If you only want to match space and tab, use [ \t] +instead. + ++++ +** 'min' and 'max' no longer round their results. +Formerly, they returned a floating-point value if any argument was +floating-point, which was sometimes numerically incorrect. For +example, on a 64-bit host (max 1e16 10000000000000001) now returns its +second argument instead of its first. + ++++ +** The variable 'old-style-backquotes' has been made internal and +renamed to 'lread--old-style-backquotes'. No user code should use +this variable. + +--- +** To avoid confusion caused by "smart quotes", the reader no longer +accepts Lisp symbols which begin with the following quotation +characters: ‘’‛“”‟〞"', unless they are escaped with backslash. + ++++ +** 'default-file-name-coding-system' now defaults to a coding system +that does not process CRLF. For example, it defaults to utf-8-unix +instead of to utf-8. Before this change, Emacs would sometimes +mishandle file names containing these control characters. + ++++ +** 'file-attributes', 'file-symlink-p' and 'make-symbolic-link' no +longer quietly mutate the target of a local symbolic link, so that +Emacs can access and copy them reliably regardless of their contents. +The following changes are involved. + +--- +*** 'file-attributes' and 'file-symlink-p' no longer prepend "/:" to +symbolic links whose targets begin with "/" and contain ":". For +example, if a symbolic link "x" has a target "/y:z:", '(file-symlink-p +"x")' now returns "/y:z:" rather than "/:/y:z:". + +--- +*** 'make-symbolic-link' no longer looks for file name handlers of +target when creating a symbolic link. For example, +'(make-symbolic-link "/y:z:" "x")' now creates a symbolic link to +"/y:z:" instead of failing. + ++++ +*** 'make-symbolic-link' removes the remote part of a link target if +target and newname have the same remote part. For example, +'(make-symbolic-link "/x:y:a" "/x:y:b")' creates a link with the +literal string "a"; and '(make-symbolic-link "/x:y:a" "/x:z:b")' +creates a link with the literal string "/x:y:a" instead of failing. + ++++ +*** 'make-symbolic-link' now expands a link target with leading "~" +only when the optional third arg is an integer, as when invoked +interactively. For example, '(make-symbolic-link "~y" "x")' now +creates a link with target the literal string "~y"; to get the old +behavior, use '(make-symbolic-link (expand-file-name "~y") "x")'. To +avoid this expansion in interactive use, you can now prefix the link +target with "/:". For example, '(make-symbolic-link "/:~y" "x" 1)' +now creates a link to literal "~y". + ++++ +** 'file-truename' returns a quoted file name if the target of a +symbolic link has remote file name syntax. + ++++ +** Module functions are now implemented slightly differently; in +particular, the function 'internal--module-call' has been removed. +Code that depends on undocumented internals of the module system might +break. + +--- +** The argument LOCKNAME of 'write-region' is propagated to file name +handlers now. + +--- +** When built against recent versions of GTK+, Emacs always uses +gtk_window_move for moving frames and ignores the value of the +variable 'x-gtk-use-window-move'. The variable is now obsolete. + ++++ +** Several functions that create or rename files now treat their +destination argument specially only when it is a directory name, i.e., +when it ends in '/' on GNU and other POSIX-like systems. When the +destination argument D of one of these functions is an existing +directory and the intent is to act on an entry in that directory, D +should now be a directory name. For example, (rename-file "e" "f/") +renames to 'f/e'. Although this formerly happened sometimes even when +D was not a directory name, as in (rename-file "e" "f") where 'f' +happened to be a directory, the old behavior often contradicted the +documentation and had inherent races that led to security holes. A +call like (rename-file C D) that used the old, undocumented behavior +can be written as (rename-file C (file-name-as-directory D)), a +formulation portable to both older and newer versions of Emacs. +Affected functions include add-name-to-file, copy-directory, +copy-file, format-write-file, gnus-copy-file, make-symbolic-link, +rename-file, thumbs-rename-images, and write-file. + +--- +** The list returned by 'overlays-at' is now in decreasing priority order. +The documentation of this function always said the order should be +that of decreasing priority, if the 2nd argument of the function is +non-nil, but the code returned the list in the increasing order of +priority instead. Now the code does what the documentation says it +should do. + +--- +** The function 'eldoc-message' now accepts a single argument. +Programs that called it with multiple arguments before should pass +them through 'format' first. Even that is discouraged: for ElDoc +support, you should set 'eldoc-documentation-function' instead of +calling 'eldoc-message' directly. + +* Lisp Changes in Emacs 26.1 + ++++ +** The function 'assoc' now takes an optional third argument TESTFN. +This argument, when non-nil, is used for comparison instead of +'equal'. + ++++ +** New optional argument TESTFN in 'alist-get', 'map-elt' and 'map-put'. +If non-nil, the argument specifies a function to use for comparison, +instead of, respectively, 'assq' and 'eql'. + ++++ +** New function 'seq-set-equal-p' to check if SEQUENCE1 and SEQUENCE2 +contain the same elements, regardless of the order. + ++++ +** The new function 'mapbacktrace' applies a function to all frames of +the current stack trace. + ++++ +** The new function 'file-name-case-insensitive-p' tests whether a +given file is on a case-insensitive filesystem. + ++++ +** Several accessors for the value returned by 'file-attributes' +have been added. They are: 'file-attribute-type', +'file-attribute-link-number', 'file-attribute-user-id', +'file-attribute-group-id', 'file-attribute-access-time', +'file-attribute-modification-time', +'file-attribute-status-change-time', 'file-attribute-size', +'file-attribute-modes', 'file-attribute-inode-number', +'file-attribute-device-number' and 'file-attribute-collect'. + ++++ +** The new function 'buffer-hash' computes a fast, non-consing hash of +a buffer's contents. + ++++ +** 'interrupt-process' now consults the list 'interrupt-process-functions', +to determine which function has to be called in order to deliver the +SIGINT signal. This allows Tramp to send the SIGINT signal to remote +asynchronous processes. The hitherto existing implementation has been +moved to 'internal-default-interrupt-process'. + ++++ +** The new function 'read-multiple-choice' prompts for multiple-choice +questions, with a handy way to display help texts. + +--- +** 'comment-indent-function' values may now return a cons to specify a +range of indentation. + ++++ +** New optional argument TEXT in 'make-temp-file'. + +--- +** New function `define-symbol-prop'. + +** Checksum/Hash + ++++ +** New function 'secure-hash-algorithms' to list the algorithms that +'secure-hash' supports. +See the node "(elisp) Checksum/Hash" in the ELisp manual for details. + ++++ +** Emacs now exposes the GnuTLS cryptographic API with the functions +'gnutls-macs' and 'gnutls-hash-mac'; 'gnutls-digests' and +'gnutls-hash-digest'; 'gnutls-ciphers' and 'gnutls-symmetric-encrypt' +and 'gnutls-symmetric-decrypt'. +See the node "(elisp) GnuTLS Cryptography" in the ELisp manual for details. + ++++ +** Emacs now supports records for user-defined types, via the new +functions 'make-record', 'record', and 'recordp'. Records are now +used internally to represent cl-defstruct and defclass instances, for +example. + ++++ +** 'save-some-buffers' now uses 'save-some-buffers-default-predicate' +to decide which buffers to ask about, if the PRED argument is nil. +The default value of 'save-some-buffers-default-predicate' is nil, +which means ask about all file-visiting buffers. + +--- +** string-(to|as|make)-(uni|multi)byte are now declared obsolete. + ++++ +** New variable 'while-no-input-ignore-events' which allow +setting which special events 'while-no-input' should ignore. +It is a list of symbols. + +--- +** New function 'undo-amalgamate-change-group' to get rid of +undo-boundaries between two states. + +--- +** New var 'definition-prefixes' is a hash table mapping prefixes to +the files where corresponding definitions can be found. This can be +used to fetch definitions that are not yet loaded, for example for +'C-h f'. + +--- +** New var 'syntax-ppss-table' to control the syntax-table used in +'syntax-ppss'. + ++++ +** 'define-derived-mode' can now specify an :after-hook form, which +gets evaluated after the new mode's hook has run. This can be used to +incorporate configuration changes made in the mode hook into the +mode's setup. + +--- +** Autoload files can be generated without timestamps, +by setting 'autoload-timestamps' to nil. +FIXME As an experiment, nil is the current default. +If no insurmountable problems before next release, it can stay that way. + +--- +** 'gnutls-boot' now takes a parameter ':complete-negotiation' that +says that negotiation should complete even on non-blocking sockets. + +--- +** There is now a new variable 'flyspell-sort-corrections-function' +that allows changing the way corrections are sorted. + +--- +** The new command 'fortune-message' has been added, which displays +fortunes in the echo area. + ++++ +** New function 'func-arity' returns information about the argument list +of an arbitrary function. This generalizes 'subr-arity' for functions +that are not built-in primitives. We recommend using this new +function instead of 'subr-arity'. + +--- +** New function 'region-bounds' can be used in the interactive spec +to provide region boundaries (for rectangular regions more than one) +to an interactively callable function as a single argument instead of +two separate arguments region-beginning and region-end. + ++++ +** 'parse-partial-sexp' state has a new element. Element 10 is +non-nil when the last character scanned might be the first character +of a two character construct, i.e., a comment delimiter or escaped +character. Its value is the syntax of that last character. + ++++ +** 'parse-partial-sexp's state, element 9, has now been confirmed as +permanent and documented, and may be used by Lisp programs. Its value +is a list of currently open parenthesis positions, starting with the +outermost parenthesis. + +--- +** 'read-color' will now display the color names using the color itself +as the background color. + +--- +** The function 'redirect-debugging-output' now works on platforms +other than GNU/Linux. + ++++ +** The new function 'string-version-lessp' compares strings by +interpreting consecutive runs of numerical characters as numbers, and +compares their numerical values. According to this predicate, +"foo2.png" is smaller than "foo12.png". + +--- +** Numeric comparisons and 'logb' no longer return incorrect answers +due to internal rounding errors. For example, (< most-positive-fixnum +(+ 1.0 most-positive-fixnum)) now correctly returns t on 64-bit hosts. + +--- +** The functions 'ffloor', 'fceiling', 'ftruncate' and 'fround' now +accept only floating-point arguments, as per their documentation. +Formerly, they quietly accepted integer arguments and sometimes +returned nonsensical answers, e.g., (< N (ffloor N)) could return t. + +--- +** On hosts like GNU/Linux x86-64 where a 'long double' fraction +contains at least EMACS_INT_WIDTH - 3 bits, 'format' no longer returns +incorrect answers due to internal rounding errors when formatting +Emacs integers with %e, %f, or %g conversions. For example, on these +hosts (eql N (string-to-number (format "%.0f" N))) now returns t for +all Emacs integers N. + +--- +** Calls that accept floating-point integers (for use on hosts with +limited integer range) now signal an error if arguments are not +integral. For example (decode-char 'ascii 0.5) now signals an error. + ++++ +** The new function 'char-from-name' converts a Unicode name string +to the corresponding character code. + ++++ +** New functions 'sxhash-eq' and 'sxhash-eql' return hash codes of a +Lisp object suitable for use with 'eq' and 'eql' correspondingly. If +two objects are 'eq' ('eql'), then the result of 'sxhash-eq' +('sxhash-eql') on them will be the same. + ++++ +** Function 'sxhash' has been renamed to 'sxhash-equal' for +consistency with the new functions. For compatibility, 'sxhash' +remains as an alias to 'sxhash-equal'. + ++++ +** 'make-hash-table' now defaults to a rehash threshold of 0.8125 +instead of 0.8, to avoid rounding glitches. + ++++ +** New function 'add-variable-watcher' can be used to call a function +when a symbol's value is changed. This is used to implement the new +debugger command 'debug-on-variable-change'. + ++++ +** Time conversion functions that accept a time zone rule argument now +allow it to be OFFSET or a list (OFFSET ABBR), where the integer +OFFSET is a count of seconds east of Universal Time, and the string +ABBR is a time zone abbreviation. The affected functions are +'current-time-string', 'current-time-zone', 'decode-time', +'format-time-string', and 'set-time-zone-rule'. + ++++ +** 'format-time-string' now formats "%q" to the calendar quarter. + ++++ +** New built-in function 'mapcan'. +It avoids unnecessary consing (and garbage collection). + ++++ +** 'car' and 'cdr' compositions 'cXXXr' and 'cXXXXr' are now part of Elisp. + ++++ +** 'gensym' is now part of Elisp. + +--- +** Low-level list functions like 'length' and 'member' now do a better +job of signaling list cycles instead of looping indefinitely. + ++++ +** The new functions 'make-nearby-temp-file' and 'temporary-file-directory' +can be used for creation of temporary files of remote or mounted directories. + ++++ +** On GNU platforms when operating on a local file, 'file-attributes' +no longer suffers from a race when called while another process is +altering the filesystem. On non-GNU platforms 'file-attributes' +attempts to detect the race, and returns nil if it does so. + ++++ +** The new function 'file-local-name' can be used to specify arguments +of remote processes. + ++++ +** The new functions 'file-name-quote', 'file-name-unquote' and +'file-name-quoted-p' can be used to quote / unquote file names with +the prefix "/:". + ++++ +** The new error 'file-missing', a subcategory of 'file-error', is now +signaled instead of 'file-error' if a file operation acts on a file +that does not exist. + ++++ +** The function 'delete-directory' no longer signals an error when +operating recursively and when some other process deletes the directory +or its files before 'delete-directory' gets to them. + ++++ +*** New error type 'user-search-failed' like 'search-failed' but +avoids debugger like 'user-error'. + ++++ +** The function 'line-number-at-pos' now takes a second optional +argument 'absolute'. If this parameter is nil, the default, this +function keeps on returning the line number taking potential narrowing +into account. If this parameter is non-nil, the function ignores +narrowing and returns the absolute line number. + +--- +** The function 'color-distance' now takes a second optional argument +'metric'. When non-nil, it should be a function of two arguments that +accepts two colors and returns a number. + +** Changes in Frame and Window Handling + ++++ +*** Resizing a frame no longer runs 'window-configuration-change-hook'. +'window-size-change-functions' should be used instead. + ++++ +*** The new function 'frame-size-changed-p' can tell whether a frame has +been resized since the last time 'window-size-change-functions' has been +run. + ++++ +*** The function 'frame-geometry' now also returns the width of a +frame's outer border. + ++++ +*** New frame parameters and changed semantics for older ones + ++++ +**** 'z-group' positions a frame above or below all others. + ++++ +**** 'min-width' and 'min-height' specify the absolute minimum size of a +frame. + ++++ +**** 'parent-frame' makes a frame the child frame of another Emacs +frame. The section "Child Frames" in the Elisp manual describes the +intrinsics of that relationship. + ++++ +**** 'delete-before' triggers deletion of one frame before that of +another. + ++++ +**** 'mouse-wheel-frame' specifies another frame whose windows shall be +scrolled instead. + ++++ +**** 'no-other-frame' has 'next-frame' and 'previous-frame' skip this +frame. + ++++ +**** 'skip-taskbar' removes a frame's icon from the taskbar and has +Alt-<TAB> skip this frame. + ++++ +**** 'no-focus-on-map' avoids that a frame gets input focus when mapped. + ++++ +**** 'no-accept-focus' means that a frame does not want to get input +focus via the mouse. + ++++ +**** 'undecorated' removes the window manager decorations from a frame. + ++++ +**** 'override-redirect' tells the window manager to disregard this +frame. + ++++ +**** 'width' and 'height' allow to specify pixel values and ratios now. + ++++ +**** 'left' and 'top' allow to specify ratios now. + ++++ +**** 'keep-ratio' preserves size and position of child frames when their +parent frame is resized. + ++++ +**** 'no-special-glyphs' suppresses display of truncation and +continuation glyphs in a frame. + ++++ +**** 'auto-hide-function' and 'minibuffer-exit' handle auto hiding of +frames and exiting from minibuffer individually. + ++++ +**** 'fit-frame-to-buffer-margins' and 'fit-frame-to-buffer-sizes' +handle fitting a frame to its buffer individually. + ++++ +**** 'drag-internal-border', 'drag-with-header-line', +'drag-with-mode-line', 'snap-width', 'top-visible' and 'bottom-visible' +allow to drag and resize frames with the mouse. + +*** The new function 'frame-list-z-order' returns a list of all frames +in Z (stacking) order. + ++++ +*** The function 'x-focus-frame' optionally tries to not activate its +frame. + ++++ +*** The variable 'focus-follows-mouse' has a third meaningful value +'auto-raise' to indicate that the window manager automatically raises a +frame when the mouse pointer enters it. + ++++ +*** The new function 'frame-restack' puts a frame above or below +another on the display. + ++++ +*** The new face 'internal-border' specifies the background of a frame's +internal border. + ++++ +*** The NORECORD argument of 'select-window' now has a meaningful value +'mark-for-redisplay' which is like any other non-nil value but marks +WINDOW for redisplay. + ++++ +*** Support for side windows is now official. +The display action function 'display-buffer-in-side-window' will +display its buffer in a side window. Functions for toggling all side +windows on a frame, changing and reversing the layout of side windows +and returning the main (major non-side) window of a frame are +provided. For details consult the section "Side Windows" in the Elisp +manual. + ++++ +*** Support for atomic windows - rectangular compositions of windows +treated by 'split-window', 'delete-window' and 'delete-other-windows' +like a single live window - is now official. For details consult the +section "Atomic Windows" in the Elisp manual. + ++++ +*** New 'display-buffer' alist entry 'window-parameters' allows to +assign window parameters to the window used for displaying the buffer. + ++++ +*** New function 'display-buffer-reuse-mode-window' is an action function +suitable for use in 'display-buffer-alist'. For example, to avoid +creating a new window when opening man pages when there's already one, +use + +(add-to-list 'display-buffer-alist + '("\\`\\*Man .*\\*\\'" . + (display-buffer-reuse-mode-window + (inhibit-same-window . nil) + (mode . Man-mode)))) + ++++ +*** New window parameter 'no-delete-other-windows' prevents that +its window gets deleted by 'delete-other-windows'. + ++++ +*** New window parameters 'mode-line-format' and 'header-line-format' +allow to override the buffer-local formats for this window. + ++++ +*** New command 'window-swap-states' swaps the states of two live +windows. + ++++ +*** New functions 'window-pixel-width-before-size-change' and +'window-pixel-height-before-size-change' support detecting which +window changed size when 'window-size-change-functions' are run. + ++++ +*** The new function 'window-lines-pixel-dimensions' returns the pixel +dimensions of a window's text lines. + ++++ +*** The new function 'window-largest-empty-rectangle' returns the +dimensions of the largest rectangular area not occupying any text in a +window's body. + ++++ +*** The semantics of 'mouse-autoselect-window' has changed slightly. +For details see the section "Mouse Window Auto-selection" in the Elisp +manual. + +--- +** 'tcl-auto-fill-mode' is now declared obsolete. Its functionality +can be replicated simply by setting 'comment-auto-fill-only-comments'. + +** New pcase pattern 'rx' to match against a rx-style regular expression. +For details, see the doc string of 'rx--pcase-macroexpander'. + +--- +** New functions to set region from secondary selection and vice versa. +The new functions 'secondary-selection-to-region' and +'secondary-selection-from-region' let you set the beginning and the +end of the region from those of the secondary selection and vise +versa. + + +* Changes in Emacs 26.1 on Non-Free Operating Systems + ++++ +** Intercepting hotkeys on Windows 7 and later now works better. +The new keyboard hooking code properly grabs system hotkeys such as +Win-* and Alt-TAB, in a way that Emacs can get at them before the +system. This makes the 'w32-register-hot-key' functionality work +again on all versions of MS-Windows starting with Windows 7. On +Windows NT and later you can now register any hotkey combination. (On +Windows 9X, the previous limitations, spelled out in the Emacs manual, +still apply.) + +--- +** 'convert-standard-filename' no longer mirrors slashes on MS-Windows. +Previously, on MS-Windows this function converted slash characters in +file names into backslashes. It no longer does that. If your Lisp +program used 'convert-standard-filename' to prepare file names to be +passed to subprocesses (which is not the recommended usage of that +function), you will now have to mirror slashes in your application +code. One possible way is this: + + (let ((start 0)) + (while (string-match "/" file-name start) + (aset file-name (match-beginning 0) ?\\) + (setq start (match-end 0)))) + +--- +** GUI sessions on MS-Windows now treat SIGINT like Posix platforms do. +The effect of delivering a Ctrl-C (SIGINT) signal to a GUI Emacs on +MS-Windows is now the same as on Posix platforms -- Emacs saves the +session and exits. In particular, this will happen if you start +emacs.exe from the Windows shell, then type Ctrl-C into that shell's +window. + +--- +** 'signal-process' supports SIGTRAP on Windows XP and later. +The 'kill' emulation on Windows now maps SIGTRAP to a call to the +'DebugBreakProcess' API. This causes the receiving process to break +execution and return control to the debugger. If no debugger is +attached to the receiving process, the call is typically ignored. +This is in contrast to the default action on POSIX Systems, where it +causes the receiving process to terminate with a core dump if no +debugger has been attached to it. + +--- +** 'set-mouse-position' and 'set-mouse-absolute-pixel-position' work +on macOS. + +--- +** Emacs can now be run as a GUI application from the command line on +macOS. + ++++ +** 'ns-appearance' and 'ns-transparent-titlebar' change the appearance +of frame decorations on macOS 10.9+. + +--- +** 'ns-use-thin-smoothing' enables thin font smoothing on macOS 10.8+. + +--- +** 'process-attributes' on Darwin systems now returns more information. + +--- +** Mousewheel and trackpad scrolling on macOS 10.7+ now behaves more +like the macOS default. The new variables 'ns-mwheel-line-height', +'ns-use-mwheel-acceleration' and 'ns-use-mwheel-momentum' can be used +to customize the behavior. + + +---------------------------------------------------------------------- +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + + +Local variables: +coding: utf-8 +mode: outline +paragraph-separate: "[ ]*$" +end: diff --git a/etc/refcards/ru-refcard.tex b/etc/refcards/ru-refcard.tex index 866dd7948f7..a168e085255 100644 --- a/etc/refcards/ru-refcard.tex +++ b/etc/refcards/ru-refcard.tex @@ -40,7 +40,7 @@ \newlength{\ColThreeWidth} \setlength{\ColThreeWidth}{25mm} -\newcommand{\versionemacs}[0]{26} % version of Emacs this is for +\newcommand{\versionemacs}[0]{27} % version of Emacs this is for \newcommand{\cyear}[0]{2017} % copyright year \newcommand\shortcopyrightnotice[0]{\vskip 1ex plus 2 fill diff --git a/lisp/autoinsert.el b/lisp/autoinsert.el index 2820c8a9afa..a43e068a4dc 100644 --- a/lisp/autoinsert.el +++ b/lisp/autoinsert.el @@ -141,14 +141,14 @@ If this contains a %s, that will be replaced by the matching rule." " .\\\" You may distribute this file under the terms of the GNU Free .\\\" Documentation License. -.TH " (file-name-base) +.TH " (file-name-base (buffer-file-name)) " " (file-name-extension (buffer-file-name)) " " (format-time-string "%Y-%m-%d ") "\n.SH NAME\n" - (file-name-base) + (file-name-base (buffer-file-name)) " \\- " str "\n.SH SYNOPSIS -.B " (file-name-base) +.B " (file-name-base (buffer-file-name)) "\n" _ " @@ -211,7 +211,7 @@ If this contains a %s, that will be replaced by the matching rule." \(provide '" - (file-name-base) + (file-name-base (buffer-file-name)) ") \;;; " (file-name-nondirectory (buffer-file-name)) " ends here\n") (("\\.texi\\(nfo\\)?\\'" . "Texinfo file skeleton") @@ -219,7 +219,7 @@ If this contains a %s, that will be replaced by the matching rule." "\\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename " - (file-name-base) ".info\n" + (file-name-base (buffer-file-name)) ".info\n" "@settitle " str " @c %**end of header @copying\n" diff --git a/lisp/electric.el b/lisp/electric.el index d7929945db2..5f4304462dd 100644 --- a/lisp/electric.el +++ b/lisp/electric.el @@ -451,6 +451,14 @@ whitespace, opening parenthesis, or quote and leaves \\=` alone." :version "26.1" :type 'boolean :safe #'booleanp :group 'electricity) +(defcustom electric-quote-replace-double nil + "Non-nil means to replace \" with an electric double quote. +Emacs replaces \" with an opening double quote after a line +break, whitespace, opening parenthesis, or quote, and with a +closing double quote otherwise." + :version "26.1" + :type 'boolean :safe #'booleanp :group 'electricity) + (defvar electric-quote-inhibit-functions () "List of functions that should inhibit electric quoting. When the variable `electric-quote-mode' is non-nil, Emacs will @@ -461,13 +469,17 @@ substitution is inhibited. The functions are called after the after the inserted character. The functions in this hook should not move point or change the current buffer.") +(defvar electric-pair-text-pairs) + (defun electric-quote-post-self-insert-function () "Function that `electric-quote-mode' adds to `post-self-insert-hook'. This requotes when a quoting key is typed." (when (and electric-quote-mode (or (eq last-command-event ?\') (and (not electric-quote-context-sensitive) - (eq last-command-event ?\`))) + (eq last-command-event ?\`)) + (and electric-quote-replace-double + (eq last-command-event ?\"))) (not (run-hook-with-args-until-success 'electric-quote-inhibit-functions)) (if (derived-mode-p 'text-mode) @@ -488,7 +500,8 @@ This requotes when a quoting key is typed." (save-excursion (let ((backtick ?\`)) (if (or (eq last-command-event ?\`) - (and electric-quote-context-sensitive + (and (or electric-quote-context-sensitive + electric-quote-replace-double) (save-excursion (backward-char) (or (bobp) (bolp) @@ -506,13 +519,19 @@ This requotes when a quoting key is typed." (setq last-command-event q<<)) ((search-backward (string backtick) (1- (point)) t) (replace-match (string q<)) - (setq last-command-event q<))) + (setq last-command-event q<)) + ((search-backward "\"" (1- (point)) t) + (replace-match (string q<<)) + (setq last-command-event q<<))) (cond ((search-backward (string q> ?') (- (point) 2) t) (replace-match (string q>>)) (setq last-command-event q>>)) ((search-backward "'" (1- (point)) t) (replace-match (string q>)) - (setq last-command-event q>)))))))))) + (setq last-command-event q>)) + ((search-backward "\"" (1- (point)) t) + (replace-match (string q>>)) + (setq last-command-event q>>)))))))))) (put 'electric-quote-post-self-insert-function 'priority 10) diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 69f03c51668..623985f44f9 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -1281,7 +1281,10 @@ ;; errors to compile time. (let ((pure-fns - '(concat symbol-name regexp-opt regexp-quote string-to-syntax))) + '(concat symbol-name regexp-opt regexp-quote string-to-syntax + string-to-char + ash lsh logb lognot logior logxor + ceiling floor))) (while pure-fns (put (car pure-fns) 'pure t) (setq pure-fns (cdr pure-fns))) diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el index bf087fc2e9a..643a65f48d9 100644 --- a/lisp/emacs-lisp/easy-mmode.el +++ b/lisp/emacs-lisp/easy-mmode.el @@ -543,6 +543,7 @@ Valid keywords and arguments are: "Define a constant M whose value is the result of `easy-mmode-define-keymap'. The M, BS, and ARGS arguments are as per that function. DOC is the constant's documentation." + (declare (indent 1)) `(defconst ,m (easy-mmode-define-keymap ,bs nil (if (boundp ',m) ,m) ,(cons 'list args)) ,doc)) @@ -569,6 +570,7 @@ the constant's documentation." (defmacro easy-mmode-defsyntax (st css doc &rest args) "Define variable ST as a syntax-table. CSS contains a list of syntax specifications of the form (CHAR . SYNTAX)." + (declare (indent 1)) `(progn (autoload 'easy-mmode-define-syntax "easy-mmode") (defconst ,st (easy-mmode-define-syntax ,css ,(cons 'list args)) ,doc))) diff --git a/lisp/files.el b/lisp/files.el index 211457ac7d7..336bbc8648d 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4484,8 +4484,8 @@ extension, the value is \"\"." ""))))) (defun file-name-base (&optional filename) - "Return the base name of the FILENAME: no directory, no extension. -FILENAME defaults to `buffer-file-name'." + "Return the base name of the FILENAME: no directory, no extension." + (declare (advertised-calling-convention (filename) "27.1")) (file-name-sans-extension (file-name-nondirectory (or filename (buffer-file-name))))) diff --git a/lisp/gnus/gnus-score.el b/lisp/gnus/gnus-score.el index 11a45dda9ad..976ac9f7f35 100644 --- a/lisp/gnus/gnus-score.el +++ b/lisp/gnus/gnus-score.el @@ -2731,8 +2731,10 @@ GROUP using BNews sys file syntax." (insert (car sfiles)) (goto-char (point-min)) ;; First remove the suffix itself. - (when (re-search-forward (concat "." score-regexp) nil t) - (replace-match "" t t) + (when (re-search-forward score-regexp nil t) + (unless (= (match-end 0) (match-beginning 0)) ; non-empty suffix + (replace-match "" t t) + (delete-char -1)) ; remove the "." before the suffix (goto-char (point-min)) (if (looking-at (regexp-quote kill-dir)) ;; If the file name was just "SCORE", `klen' is one character diff --git a/lisp/mpc.el b/lisp/mpc.el index c23d8ced716..98f4a031834 100644 --- a/lisp/mpc.el +++ b/lisp/mpc.el @@ -2403,10 +2403,38 @@ This is used so that they can be compared with `eq', which is needed for (interactive) (mpc-cmd-pause "0")) +(defun mpc-read-seek (prompt) + "Read a seek time. +Returns a string suitable for MPD \"seekcur\" protocol command." + (let* ((str (read-from-minibuffer prompt nil nil nil nil nil t)) + (seconds "\\(?1:[[:digit:]]+\\(?:\\.[[:digit:]]*\\)?\\)") + (minsec (concat "\\(?2:[[:digit:]]+\\):" seconds "?")) + (hrminsec (concat "\\(?3:[[:digit:]]+\\):\\(?:" minsec "?\\|:\\)")) + time sign) + (setq str (string-trim str)) + (when (memq (string-to-char str) '(?+ ?-)) + (setq sign (string (string-to-char str))) + (setq str (substring str 1))) + (setq time + ;; `string-to-number' returns 0 on failure + (cond + ((string-match (concat "^" hrminsec "$") str) + (+ (* 3600 (string-to-number (match-string 3 str))) + (* 60 (string-to-number (or (match-string 2 str) ""))) + (string-to-number (or (match-string 1 str) "")))) + ((string-match (concat "^" minsec "$") str) + (+ (* 60 (string-to-number (match-string 2 str))) + (string-to-number (match-string 1 str)))) + ((string-match (concat "^" seconds "$") str) + (string-to-number (match-string 1 str))) + (t (user-error "Invalid time")))) + (setq time (number-to-string time)) + (if (null sign) time (concat sign time)))) + (defun mpc-seek-current (pos) "Seek within current track." (interactive - (list (read-string "Position to go ([+-]seconds): "))) + (list (mpc-read-seek "Position to go ([+-][[H:]M:]seconds): "))) (mpc-cmd-seekcur pos)) (defun mpc-toggle-play () diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el index 318e3351237..51af455e635 100644 --- a/lisp/net/trampver.el +++ b/lisp/net/trampver.el @@ -7,7 +7,7 @@ ;; Maintainer: Michael Albinus <michael.albinus@gmx.de> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.3.3.26.1 +;; Version: 2.3.3-pre ;; This file is part of GNU Emacs. @@ -33,7 +33,7 @@ ;; should be changed only there. ;;;###tramp-autoload -(defconst tramp-version "2.3.3.26.1" +(defconst tramp-version "2.3.3-pre" "This version of Tramp.") ;;;###tramp-autoload @@ -55,7 +55,7 @@ ;; Check for Emacs version. (let ((x (if (>= emacs-major-version 24) "ok" - (format "Tramp 2.3.3.26.1 is not fit for %s" + (format "Tramp 2.3.3-pre is not fit for %s" (when (string-match "^.*$" (emacs-version)) (match-string 0 (emacs-version))))))) (unless (string-match "\\`ok\\'" x) (error "%s" x))) diff --git a/lisp/newcomment.el b/lisp/newcomment.el index 2a0f8a8ae50..2e644c3a99c 100644 --- a/lisp/newcomment.el +++ b/lisp/newcomment.el @@ -524,7 +524,7 @@ Ensure that `comment-normalize-vars' has been called before you use this." ;; comment-search-backward is only used to find the comment-column (in ;; comment-set-column) and to find the comment-start string (via ;; comment-beginning) in indent-new-comment-line, it should be harmless. - (if (not (re-search-backward comment-start-skip limit t)) + (if (not (re-search-backward comment-start-skip limit 'move)) (unless noerror (error "No comment")) (beginning-of-line) (let* ((end (match-end 0)) diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el index 5aefdea3305..02b685d240d 100644 --- a/lisp/progmodes/cc-fonts.el +++ b/lisp/progmodes/cc-fonts.el @@ -1026,7 +1026,8 @@ casts and declarations are fontified. Used on level 2 and higher." (goto-char pos))))) nil) -(defun c-font-lock-declarators (limit list types not-top) +(defun c-font-lock-declarators (limit list types not-top + &optional template-class) ;; Assuming the point is at the start of a declarator in a declaration, ;; fontify the identifier it declares. (If TYPES is set, it does this via ;; the macro `c-fontify-types-and-refs'.) @@ -1040,6 +1041,11 @@ casts and declarations are fontified. Used on level 2 and higher." ;; non-nil, we are not at the top-level ("top-level" includes being directly ;; inside a class or namespace, etc.). ;; + ;; TEMPLATE-CLASS is non-nil when the declaration is in template delimiters + ;; and was introduced by, e.g. "typename" or "class", such that if there is + ;; a default (introduced by "="), it will be fontified as a type. + ;; E.g. "<class X = Y>". + ;; ;; Nil is always returned. The function leaves point at the delimiter after ;; the last declarator it processes. ;; @@ -1112,6 +1118,13 @@ casts and declarations are fontified. Used on level 2 and higher." (goto-char next-pos) (setq pos nil) ; So as to terminate the enclosing `while' form. + (if (and template-class + (eq got-init ?=) ; C++ "<class X = Y>"? + (c-forward-token-2 1 nil limit) ; Over "=" + (let ((c-promote-possible-types t)) + (c-forward-type t))) ; Over "Y" + (setq list nil)) ; Shouldn't be needed. We can't have a list, here. + (when list ;; Jump past any initializer or function prototype to see if ;; there's a ',' to continue at. @@ -1340,8 +1353,12 @@ casts and declarations are fontified. Used on level 2 and higher." (c-backward-syntactic-ws) (and (c-simple-skip-symbol-backward) (looking-at c-paren-stmt-key)))) - t))) - + t)) + (template-class (and (eq context '<>) + (save-excursion + (goto-char match-pos) + (c-forward-syntactic-ws) + (looking-at c-template-typename-key))))) ;; Fix the `c-decl-id-start' or `c-decl-type-start' property ;; before the first declarator if it's a list. ;; `c-font-lock-declarators' handles the rest. @@ -1353,10 +1370,9 @@ casts and declarations are fontified. Used on level 2 and higher." (if (cadr decl-or-cast) 'c-decl-type-start 'c-decl-id-start))))) - (c-font-lock-declarators (min limit (point-max)) decl-list - (cadr decl-or-cast) (not toplev))) + (cadr decl-or-cast) (not toplev) template-class)) ;; A declaration has been successfully identified, so do all the ;; fontification of types and refs that've been recorded. @@ -1650,7 +1666,8 @@ casts and declarations are fontified. Used on level 2 and higher." ;; font-lock-keyword-face. It always returns NIL to inhibit this and ;; prevent a repeat invocation. See elisp/lispref page "Search-based ;; fontification". - (let ((decl-search-lim (c-determine-limit 1000)) + (let ((here (point)) + (decl-search-lim (c-determine-limit 1000)) paren-state encl-pos token-end context decl-or-cast start-pos top-level c-restricted-<>-arglists c-recognize-knr-p) ; Strictly speaking, bogus, but it @@ -1667,26 +1684,27 @@ casts and declarations are fontified. Used on level 2 and higher." (when (or (bobp) (memq (char-before) '(?\; ?{ ?}))) (setq token-end (point)) - (c-forward-syntactic-ws) - ;; We're now putatively at the declaration. - (setq start-pos (point)) - (setq paren-state (c-parse-state)) - ;; At top level or inside a "{"? - (if (or (not (setq encl-pos - (c-most-enclosing-brace paren-state))) - (eq (char-after encl-pos) ?\{)) - (progn - (setq top-level (c-at-toplevel-p)) - (let ((got-context (c-get-fontification-context - token-end nil top-level))) - (setq context (car got-context) - c-restricted-<>-arglists (cdr got-context))) - (setq decl-or-cast - (c-forward-decl-or-cast-1 token-end context nil)) - (when (consp decl-or-cast) - (goto-char start-pos) - (c-font-lock-single-decl limit decl-or-cast token-end - context top-level))))))) + (c-forward-syntactic-ws here) + (when (< (point) here) + ;; We're now putatively at the declaration. + (setq start-pos (point)) + (setq paren-state (c-parse-state)) + ;; At top level or inside a "{"? + (if (or (not (setq encl-pos + (c-most-enclosing-brace paren-state))) + (eq (char-after encl-pos) ?\{)) + (progn + (setq top-level (c-at-toplevel-p)) + (let ((got-context (c-get-fontification-context + token-end nil top-level))) + (setq context (car got-context) + c-restricted-<>-arglists (cdr got-context))) + (setq decl-or-cast + (c-forward-decl-or-cast-1 token-end context nil)) + (when (consp decl-or-cast) + (goto-char start-pos) + (c-font-lock-single-decl limit decl-or-cast token-end + context top-level)))))))) nil)) (defun c-font-lock-enclosing-decls (limit) @@ -1996,85 +2014,6 @@ on level 2 only and so aren't combined with `c-complex-decl-matchers'." 2 font-lock-type-face) `(,(concat "\\<\\(" re "\\)\\>") 1 'font-lock-type-face))) - - ;; Fontify types preceded by `c-type-prefix-kwds' (e.g. "struct"). - ,@(when (c-lang-const c-type-prefix-kwds) - `((,(byte-compile - `(lambda (limit) - (c-fontify-types-and-refs - ((c-promote-possible-types t) - ;; The font-lock package in Emacs is known to clobber - ;; `parse-sexp-lookup-properties' (when it exists). - (parse-sexp-lookup-properties - (cc-eval-when-compile - (boundp 'parse-sexp-lookup-properties)))) - (save-restriction - ;; Narrow to avoid going past the limit in - ;; `c-forward-type'. - (narrow-to-region (point) limit) - (while (re-search-forward - ,(concat "\\<\\(" - (c-make-keywords-re nil - (c-lang-const c-type-prefix-kwds)) - "\\)\\>") - limit t) - (unless (c-skip-comments-and-strings limit) - (c-forward-syntactic-ws) - ;; Handle prefix declaration specifiers. - (while - (or - (when (or (looking-at c-prefix-spec-kwds-re) - (and (c-major-mode-is 'java-mode) - (looking-at "@[A-Za-z0-9]+"))) - (c-forward-keyword-clause 1) - t) - (when (and c-opt-cpp-prefix - (looking-at - c-noise-macro-with-parens-name-re)) - (c-forward-noise-clause) - t))) - ,(if (c-major-mode-is 'c++-mode) - `(when (and (c-forward-type) - (eq (char-after) ?=)) - ;; In C++ we additionally check for a "class - ;; X = Y" construct which is used in - ;; templates, to fontify Y as a type. - (forward-char) - (c-forward-syntactic-ws) - (c-forward-type)) - `(c-forward-type)) - ))))))))) - - ;; Fontify symbols after closing braces as declaration - ;; identifiers under the assumption that they are part of - ;; declarations like "class Foo { ... } foo;". It's too - ;; expensive to check this accurately by skipping past the - ;; brace block, so we use the heuristic that it's such a - ;; declaration if the first identifier is on the same line as - ;; the closing brace. `c-font-lock-declarations' will later - ;; override it if it turns out to be an new declaration, but - ;; it will be wrong if it's an expression (see the test - ;; decls-8.cc). -;; ,@(when (c-lang-const c-opt-block-decls-with-vars-key) -;; `((,(c-make-font-lock-search-function -;; (concat "}" -;; (c-lang-const c-single-line-syntactic-ws) -;; "\\(" ; 1 + c-single-line-syntactic-ws-depth -;; (c-lang-const c-type-decl-prefix-key) -;; "\\|" -;; (c-lang-const c-symbol-key) -;; "\\)") -;; `((c-font-lock-declarators limit t nil) ; That nil says use `font-lock-variable-name-face'; -;; ; t would mean `font-lock-function-name-face'. -;; (progn -;; (c-put-char-property (match-beginning 0) 'c-type -;; 'c-decl-id-start) -;; ; 'c-decl-type-start) -;; (goto-char (match-beginning -;; ,(1+ (c-lang-const -;; c-single-line-syntactic-ws-depth))))) -;; (goto-char (match-end 0))))))) - ;; Fontify the type in C++ "new" expressions. ,@(when (c-major-mode-is 'c++-mode) ;; This pattern is a probably a "(MATCHER . ANCHORED-HIGHLIGHTER)" diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el index 7a285f93d34..9495d602e09 100644 --- a/lisp/progmodes/cc-langs.el +++ b/lisp/progmodes/cc-langs.el @@ -1891,6 +1891,17 @@ the type of that expression." t (c-make-keywords-re t (c-lang-const c-typeof-kwds))) (c-lang-defvar c-typeof-key (c-lang-const c-typeof-key)) +(c-lang-defconst c-template-typename-kwds + "Keywords which, within a template declaration, can introduce a +declaration with a type as a default value. This is used only in +C++ Mode, e.g. \"<typename X = Y>\"." + t nil + c++ '("class" "typename")) + +(c-lang-defconst c-template-typename-key + t (c-make-keywords-re t (c-lang-const c-template-typename-kwds))) +(c-lang-defvar c-template-typename-key (c-lang-const c-template-typename-key)) + (c-lang-defconst c-type-prefix-kwds "Keywords where the following name - if any - is a type name, and where the keyword together with the symbol works as a type in diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el index abd77bd973d..e956637572c 100644 --- a/lisp/progmodes/cperl-mode.el +++ b/lisp/progmodes/cperl-mode.el @@ -2314,7 +2314,7 @@ to nil." nil t)))) ; Only one (progn (forward-word-strictly 1) - (setq name (file-name-base) + (setq name (file-name-base (buffer-file-name)) p (point)) (insert " NAME\n\n" name " - \n\n=head1 SYNOPSIS\n\n\n\n" diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el new file mode 100644 index 00000000000..df1a0750cfb --- /dev/null +++ b/lisp/progmodes/flymake-proc.el @@ -0,0 +1,1100 @@ +;;; flymake-proc.el --- Flymake for external syntax checker processes -*- lexical-binding: t; -*- + +;; Copyright (C) 2003-2017 Free Software Foundation, Inc. + +;; Author: Pavel Kobyakov <pk_at_work@yahoo.com> +;; Maintainer: Leo Liu <sdl.web@gmail.com> +;; Version: 0.3 +;; Keywords: c languages tools + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; Flymake is a minor Emacs mode performing on-the-fly syntax checks. +;; +;; This file contains the most original implementation of flymake's +;; main source of on-the-fly diagnostic info, the external syntax +;; checker backend. +;; +;;; Bugs/todo: + +;; - Only uses "Makefile", not "makefile" or "GNUmakefile" +;; (from http://bugs.debian.org/337339). + +;;; Code: + +(require 'flymake-ui) + +(defcustom flymake-compilation-prevents-syntax-check t + "If non-nil, don't start syntax check if compilation is running." + :group 'flymake + :type 'boolean) + +(defcustom flymake-xml-program + (if (executable-find "xmlstarlet") "xmlstarlet" "xml") + "Program to use for XML validation." + :type 'file + :group 'flymake + :version "24.4") + +(defcustom flymake-master-file-dirs '("." "./src" "./UnitTest") + "Dirs where to look for master files." + :group 'flymake + :type '(repeat (string))) + +(defcustom flymake-master-file-count-limit 32 + "Max number of master files to check." + :group 'flymake + :type 'integer) + +(defcustom flymake-allowed-file-name-masks + '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init) + ("\\.xml\\'" flymake-xml-init) + ("\\.html?\\'" flymake-xml-init) + ("\\.cs\\'" flymake-simple-make-init) + ("\\.p[ml]\\'" flymake-perl-init) + ("\\.php[345]?\\'" flymake-php-init) + ("\\.h\\'" flymake-master-make-header-init flymake-master-cleanup) + ("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup) + ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup) + ("\\.tex\\'" flymake-simple-tex-init) + ("\\.idl\\'" flymake-simple-make-init) + ;; ("\\.cpp\\'" 1) + ;; ("\\.java\\'" 3) + ;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'") + ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2)) + ;; ("\\.idl\\'" 1) + ;; ("\\.odl\\'" 1) + ;; ("[0-9]+\\.tex\\'" 2 ("\\.tex\\'") + ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 )) + ;; ("\\.tex\\'" 1) + ) + "Files syntax checking is allowed for. +This is an alist with elements of the form: + REGEXP [INIT [CLEANUP [NAME]]] +REGEXP is a regular expression that matches a file name. +INIT is the init function to use, missing means disable `flymake-mode'. +CLEANUP is the cleanup function to use, default `flymake-simple-cleanup'. +NAME is the file name function to use, default `flymake-get-real-file-name'." + :group 'flymake + :type '(alist :key-type (regexp :tag "File regexp") + :value-type + (list :tag "Handler functions" + (choice :tag "Init function" + (const :tag "disable" nil) + function) + (choice :tag "Cleanup function" + (const :tag "flymake-simple-cleanup" nil) + function) + (choice :tag "Name function" + (const :tag "flymake-get-real-file-name" nil) + function)))) + +(defvar flymake-processes nil + "List of currently active flymake processes.") + +(defvar-local flymake-output-residual nil) + +(defun flymake-get-file-name-mode-and-masks (file-name) + "Return the corresponding entry from `flymake-allowed-file-name-masks'." + (unless (stringp file-name) + (error "Invalid file-name")) + (let ((fnm flymake-allowed-file-name-masks) + (mode-and-masks nil)) + (while (and (not mode-and-masks) fnm) + (let ((item (pop fnm))) + (when (string-match (car item) file-name) + (setq mode-and-masks item)))) ; (cdr item) may be nil + (setq mode-and-masks (cdr mode-and-masks)) + (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks)) + mode-and-masks)) + +(defun flymake-proc-can-syntax-check-buffer () + "Determine whether we can syntax check current buffer. +Return nil if we cannot, non-nil if +we can." + (and buffer-file-name + (if (flymake-get-init-function buffer-file-name) t nil))) + +(defun flymake-get-init-function (file-name) + "Return init function to be used for the file." + (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name)))) + ;;(flymake-log 0 "calling %s" init-f) + ;;(funcall init-f (current-buffer)) + init-f)) + +(defun flymake-get-cleanup-function (file-name) + "Return cleanup function to be used for the file." + (or (nth 1 (flymake-get-file-name-mode-and-masks file-name)) + 'flymake-simple-cleanup)) + +(defun flymake-get-real-file-name-function (file-name) + (or (nth 2 (flymake-get-file-name-mode-and-masks file-name)) + 'flymake-get-real-file-name)) + +(defvar flymake-find-buildfile-cache (make-hash-table :test #'equal)) + +(defun flymake-get-buildfile-from-cache (dir-name) + "Look up DIR-NAME in cache and return its associated value. +If DIR-NAME is not found, return nil." + (gethash dir-name flymake-find-buildfile-cache)) + +(defun flymake-add-buildfile-to-cache (dir-name buildfile) + "Associate DIR-NAME with BUILDFILE in the buildfile cache." + (puthash dir-name buildfile flymake-find-buildfile-cache)) + +(defun flymake-clear-buildfile-cache () + "Clear the buildfile cache." + (clrhash flymake-find-buildfile-cache)) + +(defun flymake-find-buildfile (buildfile-name source-dir-name) + "Find buildfile starting from current directory. +Buildfile includes Makefile, build.xml etc. +Return its file name if found, or nil if not found." + (or (flymake-get-buildfile-from-cache source-dir-name) + (let* ((file (locate-dominating-file source-dir-name buildfile-name))) + (if file + (progn + (flymake-log 3 "found buildfile at %s" file) + (flymake-add-buildfile-to-cache source-dir-name file) + file) + (progn + (flymake-log 3 "buildfile for %s not found" source-dir-name) + nil))))) + +(defun flymake-fix-file-name (name) + "Replace all occurrences of `\\' with `/'." + (when name + (setq name (expand-file-name name)) + (setq name (abbreviate-file-name name)) + (setq name (directory-file-name name)) + name)) + +(defun flymake-same-files (file-name-one file-name-two) + "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file. +Return t if so, nil if not." + (equal (flymake-fix-file-name file-name-one) + (flymake-fix-file-name file-name-two))) + +;; This is bound dynamically to pass a parameter to a sort predicate below +(defvar flymake-included-file-name) + +(defun flymake-find-possible-master-files (file-name master-file-dirs masks) + "Find (by name and location) all possible master files. + +Name is specified by FILE-NAME and location is specified by +MASTER-FILE-DIRS. Master files include .cpp and .c for .h. +Files are searched for starting from the .h directory and max +max-level parent dirs. File contents are not checked." + (let* ((dirs master-file-dirs) + (files nil) + (done nil)) + + (while (and (not done) dirs) + (let* ((dir (expand-file-name (car dirs) (file-name-directory file-name))) + (masks masks)) + (while (and (file-exists-p dir) (not done) masks) + (let* ((mask (car masks)) + (dir-files (directory-files dir t mask))) + + (flymake-log 3 "dir %s, %d file(s) for mask %s" + dir (length dir-files) mask) + (while (and (not done) dir-files) + (when (not (file-directory-p (car dir-files))) + (setq files (cons (car dir-files) files)) + (when (>= (length files) flymake-master-file-count-limit) + (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit) + (setq done t))) + (setq dir-files (cdr dir-files)))) + (setq masks (cdr masks)))) + (setq dirs (cdr dirs))) + (when files + (let ((flymake-included-file-name (file-name-nondirectory file-name))) + (setq files (sort files 'flymake-master-file-compare)))) + (flymake-log 3 "found %d possible master file(s)" (length files)) + files)) + +(defun flymake-master-file-compare (file-one file-two) + "Compare two files specified by FILE-ONE and FILE-TWO. +This function is used in sort to move most possible file names +to the beginning of the list (File.h -> File.cpp moved to top)." + (and (equal (file-name-sans-extension flymake-included-file-name) + (file-name-base file-one)) + (not (equal file-one file-two)))) + +(defvar flymake-check-file-limit 8192 + "Maximum number of chars to look at when checking possible master file. +Nil means search the entire file.") + +(defun flymake-check-patch-master-file-buffer + (master-file-temp-buffer + master-file-name patched-master-file-name + source-file-name patched-source-file-name + include-dirs regexp) + "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME. +If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME +instead of SOURCE-FILE-NAME. + +For example, foo.cpp is a master file if it includes foo.h. + +When a buffer for MASTER-FILE-NAME exists, use it as a source +instead of reading master file from disk." + (let* ((source-file-nondir (file-name-nondirectory source-file-name)) + (source-file-extension (file-name-extension source-file-nondir)) + (source-file-nonext (file-name-sans-extension source-file-nondir)) + (found nil) + (inc-name nil) + (search-limit flymake-check-file-limit)) + (setq regexp + (format regexp ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\"" + ;; Hack for tex files, where \include often excludes .tex. + ;; Maybe this is safe generally. + (if (and (> (length source-file-extension) 1) + (string-equal source-file-extension "tex")) + (format "%s\\(?:\\.%s\\)?" + (regexp-quote source-file-nonext) + (regexp-quote source-file-extension)) + (regexp-quote source-file-nondir)))) + (unwind-protect + (with-current-buffer master-file-temp-buffer + (if (or (not search-limit) + (> search-limit (point-max))) + (setq search-limit (point-max))) + (flymake-log 3 "checking %s against regexp %s" + master-file-name regexp) + (goto-char (point-min)) + (while (and (< (point) search-limit) + (re-search-forward regexp search-limit t)) + (let ((match-beg (match-beginning 1)) + (match-end (match-end 1))) + + (flymake-log 3 "found possible match for %s" source-file-nondir) + (setq inc-name (match-string 1)) + (and (> (length source-file-extension) 1) + (string-equal source-file-extension "tex") + (not (string-match (format "\\.%s\\'" source-file-extension) + inc-name)) + (setq inc-name (concat inc-name "." source-file-extension))) + (when (eq t (compare-strings + source-file-nondir nil nil + inc-name (- (length inc-name) + (length source-file-nondir)) nil)) + (flymake-log 3 "inc-name=%s" inc-name) + (when (flymake-check-include source-file-name inc-name + include-dirs) + (setq found t) + ;; replace-match is not used here as it fails in + ;; XEmacs with 'last match not a buffer' error as + ;; check-includes calls replace-in-string + (flymake-replace-region + match-beg match-end + (file-name-nondirectory patched-source-file-name)))) + (forward-line 1))) + (when found + (flymake-save-buffer-in-file patched-master-file-name))) + ;;+(flymake-log 3 "killing buffer %s" + ;; (buffer-name master-file-temp-buffer)) + (kill-buffer master-file-temp-buffer)) + ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found) + (when found + (flymake-log 2 "found master file %s" master-file-name)) + found)) + +;;; XXX: remove +(defun flymake-replace-region (beg end rep) + "Replace text in BUFFER in region (BEG END) with REP." + (save-excursion + (goto-char end) + ;; Insert before deleting, so as to better preserve markers's positions. + (insert rep) + (delete-region beg end))) + +(defun flymake-read-file-to-temp-buffer (file-name) + "Insert contents of FILE-NAME into newly created temp buffer." + (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name)))))) + (with-current-buffer temp-buffer + (insert-file-contents file-name)) + temp-buffer)) + +(defun flymake-copy-buffer-to-temp-buffer (buffer) + "Copy contents of BUFFER into newly created temp buffer." + (with-current-buffer + (get-buffer-create (generate-new-buffer-name + (concat "flymake:" (buffer-name buffer)))) + (insert-buffer-substring buffer) + (current-buffer))) + +(defun flymake-check-include (source-file-name inc-name include-dirs) + "Check if SOURCE-FILE-NAME can be found in include path. +Return t if it can be found via include path using INC-NAME." + (if (file-name-absolute-p inc-name) + (flymake-same-files source-file-name inc-name) + (while (and include-dirs + (not (flymake-same-files + source-file-name + (concat (file-name-directory source-file-name) + "/" (car include-dirs) + "/" inc-name)))) + (setq include-dirs (cdr include-dirs))) + include-dirs)) + +(defun flymake-find-buffer-for-file (file-name) + "Check if there exists a buffer visiting FILE-NAME. +Return t if so, nil if not." + (let ((buffer-name (get-file-buffer file-name))) + (if buffer-name + (get-buffer buffer-name)))) + +(defun flymake-create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp) + "Save SOURCE-FILE-NAME with a different name. +Find master file, patch and save it." + (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks)) + (master-file-count (length possible-master-files)) + (idx 0) + (temp-buffer nil) + (master-file-name nil) + (patched-master-file-name nil) + (found nil)) + + (while (and (not found) (< idx master-file-count)) + (setq master-file-name (nth idx possible-master-files)) + (setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master")) + (if (flymake-find-buffer-for-file master-file-name) + (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name))) + (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name))) + (setq found + (flymake-check-patch-master-file-buffer + temp-buffer + master-file-name + patched-master-file-name + source-file-name + patched-source-file-name + (funcall get-incl-dirs-f (file-name-directory master-file-name)) + include-regexp)) + (setq idx (1+ idx))) + (if found + (list master-file-name patched-master-file-name) + (progn + (flymake-log 3 "none of %d master file(s) checked includes %s" master-file-count + (file-name-nondirectory source-file-name)) + nil)))) + +(defun flymake-save-buffer-in-file (file-name) + "Save the entire buffer contents into file FILE-NAME. +Create parent directories as needed." + (make-directory (file-name-directory file-name) 1) + (write-region nil nil file-name nil 566) + (flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name)) + +(defun flymake-process-filter (process output) + "Parse OUTPUT and highlight error lines. +It's flymake process filter." + (let ((source-buffer (process-buffer process))) + + (flymake-log 3 "received %d byte(s) of output from process %d" + (length output) (process-id process)) + (when (buffer-live-p source-buffer) + (with-current-buffer source-buffer + (flymake-parse-output-and-residual output))))) + +(defun flymake-process-sentinel (process _event) + "Sentinel for syntax check buffers." + (when (memq (process-status process) '(signal exit)) + (let* ((exit-status (process-exit-status process)) + (command (process-command process)) + (source-buffer (process-buffer process)) + (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer)))) + + (flymake-log 2 "process %d exited with code %d" + (process-id process) exit-status) + (condition-case err + (progn + (flymake-log 3 "cleaning up using %s" cleanup-f) + (when (buffer-live-p source-buffer) + (with-current-buffer source-buffer + (funcall cleanup-f))) + + (delete-process process) + (setq flymake-processes (delq process flymake-processes)) + + (when (buffer-live-p source-buffer) + (with-current-buffer source-buffer + + (flymake-parse-residual) + (flymake-post-syntax-check exit-status command) + (setq flymake-is-running nil)))) + (error + (let ((err-str (format "Error in process sentinel for buffer %s: %s" + source-buffer (error-message-string err)))) + (flymake-log 0 err-str) + (with-current-buffer source-buffer + (setq flymake-is-running nil)))))))) + +(defun flymake-post-syntax-check (exit-status command) + (save-restriction + (widen) + (setq flymake-err-info flymake-new-err-info) + (setq flymake-new-err-info nil) + (setq flymake-err-info + (flymake-fix-line-numbers + flymake-err-info 1 (count-lines (point-min) (point-max)))) + (flymake-delete-own-overlays) + (flymake-highlight-err-lines flymake-err-info) + (let (err-count warn-count) + (setq err-count (flymake-get-err-count flymake-err-info "e")) + (setq warn-count (flymake-get-err-count flymake-err-info "w")) + (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)" + (buffer-name) err-count warn-count + (- (float-time) flymake-check-start-time)) + (setq flymake-check-start-time nil) + + (if (and (equal 0 err-count) (equal 0 warn-count)) + (if (equal 0 exit-status) + (flymake-report-status "" "") ; PASSED + (if (not flymake-check-was-interrupted) + (flymake-report-fatal-status "CFGERR" + (format "Configuration error has occurred while running %s" command)) + (flymake-report-status nil ""))) ; "STOPPED" + (flymake-report-status (format "%d/%d" err-count warn-count) ""))))) + +(defun flymake-parse-output-and-residual (output) + "Split OUTPUT into lines, merge in residual if necessary." + (let* ((buffer-residual flymake-output-residual) + (total-output (if buffer-residual (concat buffer-residual output) output)) + (lines-and-residual (flymake-split-output total-output)) + (lines (nth 0 lines-and-residual)) + (new-residual (nth 1 lines-and-residual))) + (setq flymake-output-residual new-residual) + (setq flymake-new-err-info + (flymake-parse-err-lines + flymake-new-err-info lines)))) + +(defun flymake-parse-residual () + "Parse residual if it's non empty." + (when flymake-output-residual + (setq flymake-new-err-info + (flymake-parse-err-lines + flymake-new-err-info + (list flymake-output-residual))) + (setq flymake-output-residual nil))) + +(defun flymake-fix-line-numbers (err-info-list min-line max-line) + "Replace line numbers with fixed value. +If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE. +If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE. +The reason for this fix is because some compilers might report +line number outside the file being compiled." + (let* ((count (length err-info-list)) + (err-info nil) + (line 0)) + (while (> count 0) + (setq err-info (nth (1- count) err-info-list)) + (setq line (flymake-er-get-line err-info)) + (when (or (< line min-line) (> line max-line)) + (setq line (if (< line min-line) min-line max-line)) + (setq err-info-list (flymake-set-at err-info-list (1- count) + (flymake-er-make-er line + (flymake-er-get-line-err-info-list err-info))))) + (setq count (1- count)))) + err-info-list) + +(defun flymake-parse-err-lines (err-info-list lines) + "Parse err LINES, store info in ERR-INFO-LIST." + (let* ((count (length lines)) + (idx 0) + (line-err-info nil) + (real-file-name nil) + (source-file-name buffer-file-name) + (get-real-file-name-f (flymake-get-real-file-name-function source-file-name))) + + (while (< idx count) + (setq line-err-info (flymake-parse-line (nth idx lines))) + (when line-err-info + (setq real-file-name (funcall get-real-file-name-f + (flymake-ler-file line-err-info))) + (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name)) + + (when (flymake-same-files real-file-name source-file-name) + (setq line-err-info (flymake-ler-set-file line-err-info nil)) + (setq err-info-list (flymake-add-err-info err-info-list line-err-info)))) + (flymake-log 3 "parsed `%s', %s line-err-info" (nth idx lines) (if line-err-info "got" "no")) + (setq idx (1+ idx))) + err-info-list)) + +(defun flymake-split-output (output) + "Split OUTPUT into lines. +Return last one as residual if it does not end with newline char. +Returns ((LINES) RESIDUAL)." + (when (and output (> (length output) 0)) + (let* ((lines (split-string output "[\n\r]+" t)) + (complete (equal "\n" (char-to-string (aref output (1- (length output)))))) + (residual nil)) + (when (not complete) + (setq residual (car (last lines))) + (setq lines (butlast lines))) + (list lines residual)))) + +(defun flymake-reformat-err-line-patterns-from-compile-el (original-list) + "Grab error line patterns from ORIGINAL-LIST in compile.el format. +Convert it to flymake internal format." + (let* ((converted-list '())) + (dolist (item original-list) + (setq item (cdr item)) + (let ((regexp (nth 0 item)) + (file (nth 1 item)) + (line (nth 2 item)) + (col (nth 3 item))) + (if (consp file) (setq file (car file))) + (if (consp line) (setq line (car line))) + (if (consp col) (setq col (car col))) + + (when (not (functionp line)) + (setq converted-list (cons (list regexp file line col) converted-list))))) + converted-list)) + +(require 'compile) + +(defvar flymake-err-line-patterns ; regexp file-idx line-idx col-idx (optional) text-idx(optional), match-end to end of string is error text + (append + '( + ;; MS Visual C++ 6.0 + ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) : \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)" + 1 3 nil 4) + ;; jikes + ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:[0-9]+: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)" + 1 3 nil 4) + ;; MS midl + ("midl[ ]*:[ ]*\\(command line error .*\\)" + nil nil nil 1) + ;; MS C# + ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+): \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)" + 1 3 nil 4) + ;; perl + ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1) + ;; PHP + ("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 2 3 nil 1) + ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1) + ;; ant/javac. Note this also matches gcc warnings! + (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\)\\(?::[0-9]+\\)?:[ \t\n]*\\(.+\\)" + 2 4 nil 5)) + ;; compilation-error-regexp-alist) + (flymake-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist)) + "Patterns for matching error/warning lines. Each pattern has the form +\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX). +Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns +from compile.el") + +(define-obsolete-variable-alias 'flymake-warning-re 'flymake-warning-predicate "24.4") +(defvar flymake-warning-predicate "^[wW]arning" + "Predicate matching against error text to detect a warning. +Takes a single argument, the error's text and should return non-nil +if it's a warning. +Instead of a function, it can also be a regular expression.") + +(defun flymake-parse-line (line) + "Parse LINE to see if it is an error or warning. +Return its components if so, nil otherwise." + (let ((raw-file-name nil) + (line-no 0) + (err-type "e") + (err-text nil) + (patterns flymake-err-line-patterns) + (matched nil)) + (while (and patterns (not matched)) + (when (string-match (car (car patterns)) line) + (let* ((file-idx (nth 1 (car patterns))) + (line-idx (nth 2 (car patterns)))) + + (setq raw-file-name (if file-idx (match-string file-idx line) nil)) + (setq line-no (if line-idx (string-to-number + (match-string line-idx line)) 0)) + (setq err-text (if (> (length (car patterns)) 4) + (match-string (nth 4 (car patterns)) line) + (flymake-patch-err-text + (substring line (match-end 0))))) + (if (null err-text) + (setq err-text "<no error text>") + (when (cond ((stringp flymake-warning-predicate) + (string-match flymake-warning-predicate err-text)) + ((functionp flymake-warning-predicate) + (funcall flymake-warning-predicate err-text))) + (setq err-type "w"))) + (flymake-log + 3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s" + file-idx line-idx raw-file-name line-no err-text) + (setq matched t))) + (setq patterns (cdr patterns))) + (if matched + (flymake-ler-make-ler raw-file-name line-no err-type err-text) + ()))) + +(defun flymake-get-project-include-dirs-imp (basedir) + "Include dirs for the project current file belongs to." + (if (flymake-get-project-include-dirs-from-cache basedir) + (progn + (flymake-get-project-include-dirs-from-cache basedir)) + ;;else + (let* ((command-line (concat "make -C " + (shell-quote-argument basedir) + " DUMPVARS=INCLUDE_DIRS dumpvars")) + (output (shell-command-to-string command-line)) + (lines (split-string output "\n" t)) + (count (length lines)) + (idx 0) + (inc-dirs nil)) + (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx lines)))) + (setq idx (1+ idx))) + (when (< idx count) + (let* ((inc-lines (split-string (nth idx lines) " *-I" t)) + (inc-count (length inc-lines))) + (while (> inc-count 0) + (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines))) + (push (replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs)) + (setq inc-count (1- inc-count))))) + (flymake-add-project-include-dirs-to-cache basedir inc-dirs) + inc-dirs))) + +(defvar flymake-get-project-include-dirs-function #'flymake-get-project-include-dirs-imp + "Function used to get project include dirs, one parameter: basedir name.") + +(defun flymake-get-project-include-dirs (basedir) + (funcall flymake-get-project-include-dirs-function basedir)) + +(defun flymake-get-system-include-dirs () + "System include dirs - from the `INCLUDE' env setting." + (let* ((includes (getenv "INCLUDE"))) + (if includes (split-string includes path-separator t) nil))) + +(defvar flymake-project-include-dirs-cache (make-hash-table :test #'equal)) + +(defun flymake-get-project-include-dirs-from-cache (base-dir) + (gethash base-dir flymake-project-include-dirs-cache)) + +(defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs) + (puthash base-dir include-dirs flymake-project-include-dirs-cache)) + +(defun flymake-clear-project-include-dirs-cache () + (clrhash flymake-project-include-dirs-cache)) + +(defun flymake-get-include-dirs (base-dir) + "Get dirs to use when resolving local file names." + (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs)))) + include-dirs)) + +;; (defun flymake-restore-formatting () +;; "Remove any formatting made by flymake." +;; ) + +;; (defun flymake-get-program-dir (buffer) +;; "Get dir to start program in." +;; (unless (bufferp buffer) +;; (error "Invalid buffer")) +;; (with-current-buffer buffer +;; default-directory)) + +(defun flymake-safe-delete-file (file-name) + (when (and file-name (file-exists-p file-name)) + (delete-file file-name) + (flymake-log 1 "deleted file %s" file-name))) + +(defun flymake-safe-delete-directory (dir-name) + (condition-case nil + (progn + (delete-directory dir-name) + (flymake-log 1 "deleted dir %s" dir-name)) + (error + (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name)))) + +(defun flymake-proc-start-syntax-check () + "Start syntax checking for current buffer." + (interactive) + (flymake-log 3 "flymake is running: %s" flymake-is-running) + (when (not flymake-is-running) + (when (or (not flymake-compilation-prevents-syntax-check) + (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP") + (flymake-clear-buildfile-cache) + (flymake-clear-project-include-dirs-cache) + + (setq flymake-check-was-interrupted nil) + + (let* ((source-file-name buffer-file-name) + (init-f (flymake-get-init-function source-file-name)) + (cleanup-f (flymake-get-cleanup-function source-file-name)) + (cmd-and-args (funcall init-f)) + (cmd (nth 0 cmd-and-args)) + (args (nth 1 cmd-and-args)) + (dir (nth 2 cmd-and-args))) + (if (not cmd-and-args) + (progn + (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name) + (funcall cleanup-f)) + (progn + (setq flymake-last-change-time nil) + (flymake-start-syntax-check-process cmd args dir))))))) + +(defun flymake-start-syntax-check-process (cmd args dir) + "Start syntax check process." + (condition-case err + (let* ((process + (let ((default-directory (or dir default-directory))) + (when dir + (flymake-log 3 "starting process on dir %s" dir)) + (apply 'start-file-process + "flymake-proc" (current-buffer) cmd args)))) + (set-process-sentinel process 'flymake-process-sentinel) + (set-process-filter process 'flymake-process-filter) + (set-process-query-on-exit-flag process nil) + (push process flymake-processes) + + (setq flymake-is-running t) + (setq flymake-last-change-time nil) + (setq flymake-check-start-time (float-time)) + + (flymake-report-status nil "*") + (flymake-log 2 "started process %d, command=%s, dir=%s" + (process-id process) (process-command process) + default-directory) + process) + (error + (let* ((err-str + (format-message + "Failed to launch syntax check process `%s' with args %s: %s" + cmd args (error-message-string err))) + (source-file-name buffer-file-name) + (cleanup-f (flymake-get-cleanup-function source-file-name))) + (flymake-log 0 err-str) + (funcall cleanup-f) + (flymake-report-fatal-status "PROCERR" err-str))))) + +(defun flymake-kill-process (proc) + "Kill process PROC." + (kill-process proc) + (let* ((buf (process-buffer proc))) + (when (buffer-live-p buf) + (with-current-buffer buf + (setq flymake-check-was-interrupted t)))) + (flymake-log 1 "killed process %d" (process-id proc))) + +(defun flymake-stop-all-syntax-checks () + "Kill all syntax check processes." + (interactive) + (while flymake-processes + (flymake-kill-process (pop flymake-processes)))) + +(defun flymake-compilation-is-running () + (and (boundp 'compilation-in-progress) + compilation-in-progress)) + +(defun flymake-compile () + "Kill all flymake syntax checks, start compilation." + (interactive) + (flymake-stop-all-syntax-checks) + (call-interactively 'compile)) + +;;;; general init-cleanup and helper routines +(defun flymake-create-temp-inplace (file-name prefix) + (unless (stringp file-name) + (error "Invalid file-name")) + (or prefix + (setq prefix "flymake")) + (let* ((ext (file-name-extension file-name)) + (temp-name (file-truename + (concat (file-name-sans-extension file-name) + "_" prefix + (and ext (concat "." ext)))))) + (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name) + temp-name)) + +(defun flymake-create-temp-with-folder-structure (file-name _prefix) + (unless (stringp file-name) + (error "Invalid file-name")) + + (let* ((dir (file-name-directory file-name)) + ;; Not sure what this slash-pos is all about, but I guess it's just + ;; trying to remove the leading / of absolute file names. + (slash-pos (string-match "/" dir)) + (temp-dir (expand-file-name (substring dir (1+ slash-pos)) + temporary-file-directory))) + + (file-truename (expand-file-name (file-name-nondirectory file-name) + temp-dir)))) + +(defun flymake-delete-temp-directory (dir-name) + "Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error." + (let* ((temp-dir temporary-file-directory) + (suffix (substring dir-name (1+ (length temp-dir))))) + + (while (> (length suffix) 0) + (setq suffix (directory-file-name suffix)) + ;;+(flymake-log 0 "suffix=%s" suffix) + (flymake-safe-delete-directory + (file-truename (expand-file-name suffix temp-dir))) + (setq suffix (file-name-directory suffix))))) + +(defvar-local flymake-temp-source-file-name nil) +(defvar-local flymake-master-file-name nil) +(defvar-local flymake-temp-master-file-name nil) +(defvar-local flymake-base-dir nil) + +(defun flymake-init-create-temp-buffer-copy (create-temp-f) + "Make a temporary copy of the current buffer, save its name in buffer data and return the name." + (let* ((source-file-name buffer-file-name) + (temp-source-file-name (funcall create-temp-f source-file-name "flymake"))) + + (flymake-save-buffer-in-file temp-source-file-name) + (setq flymake-temp-source-file-name temp-source-file-name) + temp-source-file-name)) + +(defun flymake-simple-cleanup () + "Do cleanup after `flymake-init-create-temp-buffer-copy'. +Delete temp file." + (flymake-safe-delete-file flymake-temp-source-file-name) + (setq flymake-last-change-time nil)) + +(defun flymake-get-real-file-name (file-name-from-err-msg) + "Translate file name from error message to \"real\" file name. +Return full-name. Names are real, not patched." + (let* ((real-name nil) + (source-file-name buffer-file-name) + (master-file-name flymake-master-file-name) + (temp-source-file-name flymake-temp-source-file-name) + (temp-master-file-name flymake-temp-master-file-name) + (base-dirs + (list flymake-base-dir + (file-name-directory source-file-name) + (if master-file-name (file-name-directory master-file-name)))) + (files (list (list source-file-name source-file-name) + (list temp-source-file-name source-file-name) + (list master-file-name master-file-name) + (list temp-master-file-name master-file-name)))) + + (when (equal 0 (length file-name-from-err-msg)) + (setq file-name-from-err-msg source-file-name)) + + (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files)) + ;; if real-name is nil, than file name from err msg is none of the files we've patched + (if (not real-name) + (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs))) + (if (not real-name) + (setq real-name file-name-from-err-msg)) + (setq real-name (flymake-fix-file-name real-name)) + (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name) + real-name)) + +(defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs files) + (let* ((base-dirs-count (length base-dirs)) + (file-count (length files)) + (real-name nil)) + + (while (and (not real-name) (> base-dirs-count 0)) + (setq file-count (length files)) + (while (and (not real-name) (> file-count 0)) + (let* ((this-dir (nth (1- base-dirs-count) base-dirs)) + (this-file (nth 0 (nth (1- file-count) files))) + (this-real-name (nth 1 (nth (1- file-count) files)))) + ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" this-dir this-file this-real-name file-name-from-err-msg) + (when (and this-dir this-file (flymake-same-files + (expand-file-name file-name-from-err-msg this-dir) + this-file)) + (setq real-name this-real-name))) + (setq file-count (1- file-count))) + (setq base-dirs-count (1- base-dirs-count))) + real-name)) + +(defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs) + (let* ((real-name nil)) + (if (file-name-absolute-p file-name-from-err-msg) + (setq real-name file-name-from-err-msg) + (let* ((base-dirs-count (length base-dirs))) + (while (and (not real-name) (> base-dirs-count 0)) + (let* ((full-name (expand-file-name file-name-from-err-msg + (nth (1- base-dirs-count) base-dirs)))) + (if (file-exists-p full-name) + (setq real-name full-name)) + (setq base-dirs-count (1- base-dirs-count)))))) + real-name)) + +(defun flymake-init-find-buildfile-dir (source-file-name buildfile-name) + "Find buildfile, store its dir in buffer data and return its dir, if found." + (let* ((buildfile-dir + (flymake-find-buildfile buildfile-name + (file-name-directory source-file-name)))) + (if buildfile-dir + (setq flymake-base-dir buildfile-dir) + (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name) + (flymake-report-fatal-status + "NOMK" (format "No buildfile (%s) found for %s" + buildfile-name source-file-name))))) + +(defun flymake-init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f create-temp-f master-file-masks include-regexp) + "Find master file (or buffer), create its copy along with a copy of the source file." + (let* ((source-file-name buffer-file-name) + (temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)) + (master-and-temp-master (flymake-create-master-file + source-file-name temp-source-file-name + get-incl-dirs-f create-temp-f + master-file-masks include-regexp))) + + (if (not master-and-temp-master) + (progn + (flymake-log 1 "cannot find master file for %s" source-file-name) + (flymake-report-status "!" "") ; NOMASTER + nil) + (setq flymake-master-file-name (nth 0 master-and-temp-master)) + (setq flymake-temp-master-file-name (nth 1 master-and-temp-master))))) + +(defun flymake-master-cleanup () + (flymake-simple-cleanup) + (flymake-safe-delete-file flymake-temp-master-file-name)) + +;;;; make-specific init-cleanup routines +(defun flymake-get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f) + "Create a command line for syntax check using GET-CMD-LINE-F." + (funcall get-cmd-line-f + (if use-relative-source + (file-relative-name source-file-name base-dir) + source-file-name) + (if use-relative-base-dir + (file-relative-name base-dir + (file-name-directory source-file-name)) + base-dir))) + +(defun flymake-get-make-cmdline (source base-dir) + (list "make" + (list "-s" + "-C" + base-dir + (concat "CHK_SOURCES=" source) + "SYNTAX_CHECK_MODE=1" + "check-syntax"))) + +(defun flymake-get-ant-cmdline (source base-dir) + (list "ant" + (list "-buildfile" + (concat base-dir "/" "build.xml") + (concat "-DCHK_SOURCES=" source) + "check-syntax"))) + +(defun flymake-simple-make-init-impl (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f) + "Create syntax check command line for a directly checked source file. +Use CREATE-TEMP-F for creating temp copy." + (let* ((args nil) + (source-file-name buffer-file-name) + (buildfile-dir (flymake-init-find-buildfile-dir source-file-name build-file-name))) + (if buildfile-dir + (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f))) + (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir + use-relative-base-dir use-relative-source + get-cmdline-f)))) + args)) + +(defun flymake-simple-make-init () + (flymake-simple-make-init-impl 'flymake-create-temp-inplace t t "Makefile" 'flymake-get-make-cmdline)) + +(defun flymake-master-make-init (get-incl-dirs-f master-file-masks include-regexp) + "Create make command line for a source file checked via master file compilation." + (let* ((make-args nil) + (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy + get-incl-dirs-f 'flymake-create-temp-inplace + master-file-masks include-regexp))) + (when temp-master-file-name + (let* ((buildfile-dir (flymake-init-find-buildfile-dir temp-master-file-name "Makefile"))) + (if buildfile-dir + (setq make-args (flymake-get-syntax-check-program-args + temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline))))) + make-args)) + +(defun flymake-find-make-buildfile (source-dir) + (flymake-find-buildfile "Makefile" source-dir)) + +;;;; .h/make specific +(defun flymake-master-make-header-init () + (flymake-master-make-init + 'flymake-get-include-dirs + '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'") + "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\"")) + +;;;; .java/make specific +(defun flymake-simple-make-java-init () + (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline)) + +(defun flymake-simple-ant-java-init () + (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline)) + +(defun flymake-simple-java-cleanup () + "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs." + (flymake-safe-delete-file flymake-temp-source-file-name) + (when flymake-temp-source-file-name + (flymake-delete-temp-directory + (file-name-directory flymake-temp-source-file-name)))) + +;;;; perl-specific init-cleanup routines +(defun flymake-perl-init () + (let* ((temp-file (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-inplace)) + (local-file (file-relative-name + temp-file + (file-name-directory buffer-file-name)))) + (list "perl" (list "-wc " local-file)))) + +;;;; php-specific init-cleanup routines +(defun flymake-php-init () + (let* ((temp-file (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-inplace)) + (local-file (file-relative-name + temp-file + (file-name-directory buffer-file-name)))) + (list "php" (list "-f" local-file "-l")))) + +;;;; tex-specific init-cleanup routines +(defun flymake-get-tex-args (file-name) + ;;(list "latex" (list "-c-style-errors" file-name)) + (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name))) + +(defun flymake-simple-tex-init () + (flymake-get-tex-args (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace))) + +;; Perhaps there should be a buffer-local variable flymake-master-file +;; that people can set to override this stuff. Could inherit from +;; the similar AUCTeX variable. +(defun flymake-master-tex-init () + (let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy + 'flymake-get-include-dirs-dot 'flymake-create-temp-inplace + '("\\.tex\\'") + "[ \t]*\\in\\(?:put\\|clude\\)[ \t]*{\\(.*%s\\)}"))) + (when temp-master-file-name + (flymake-get-tex-args temp-master-file-name)))) + +(defun flymake-get-include-dirs-dot (_base-dir) + '(".")) + +;;;; xml-specific init-cleanup routines +(defun flymake-xml-init () + (list flymake-xml-program + (list "val" (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-inplace)))) + + +;;;; Hook onto flymake-ui + +(add-to-list 'flymake-backends + `(flymake-proc-can-syntax-check-buffer + . + flymake-proc-start-syntax-check)) + +(provide 'flymake-proc) +;;; flymake-proc.el ends here diff --git a/lisp/progmodes/flymake-ui.el b/lisp/progmodes/flymake-ui.el new file mode 100644 index 00000000000..bf5218c41d2 --- /dev/null +++ b/lisp/progmodes/flymake-ui.el @@ -0,0 +1,634 @@ +;;; flymake-ui.el --- A universal on-the-fly syntax checker -*- lexical-binding: t; -*- + +;; Copyright (C) 2003-2017 Free Software Foundation, Inc. + +;; Author: Pavel Kobyakov <pk_at_work@yahoo.com> +;; Maintainer: Leo Liu <sdl.web@gmail.com> +;; Version: 0.3 +;; Keywords: c languages tools + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; Flymake is a minor Emacs mode performing on-the-fly syntax checks.xo +;; +;; This file contains the UI for displaying and interacting with the +;; results of such checks, as well as entry points for backends to +;; hook on to. Backends are sources of diagnostic info. +;; +;;; Code: + +(eval-when-compile (require 'cl-lib)) + +(defgroup flymake nil + "Universal on-the-fly syntax checker." + :version "23.1" + :link '(custom-manual "(flymake) Top") + :group 'tools) + +(defcustom flymake-error-bitmap '(exclamation-mark error) + "Bitmap (a symbol) used in the fringe for indicating errors. +The value may also be a list of two elements where the second +element specifies the face for the bitmap. For possible bitmap +symbols, see `fringe-bitmaps'. See also `flymake-warning-bitmap'. + +The option `flymake-fringe-indicator-position' controls how and where +this is used." + :group 'flymake + :version "24.3" + :type '(choice (symbol :tag "Bitmap") + (list :tag "Bitmap and face" + (symbol :tag "Bitmap") + (face :tag "Face")))) + +(defcustom flymake-warning-bitmap 'question-mark + "Bitmap (a symbol) used in the fringe for indicating warnings. +The value may also be a list of two elements where the second +element specifies the face for the bitmap. For possible bitmap +symbols, see `fringe-bitmaps'. See also `flymake-error-bitmap'. + +The option `flymake-fringe-indicator-position' controls how and where +this is used." + :group 'flymake + :version "24.3" + :type '(choice (symbol :tag "Bitmap") + (list :tag "Bitmap and face" + (symbol :tag "Bitmap") + (face :tag "Face")))) + +(defcustom flymake-fringe-indicator-position 'left-fringe + "The position to put flymake fringe indicator. +The value can be nil (do not use indicators), `left-fringe' or `right-fringe'. +See `flymake-error-bitmap' and `flymake-warning-bitmap'." + :group 'flymake + :version "24.3" + :type '(choice (const left-fringe) + (const right-fringe) + (const :tag "No fringe indicators" nil))) + +(defcustom flymake-start-syntax-check-on-newline t + "Start syntax check if newline char was added/removed from the buffer." + :group 'flymake + :type 'boolean) + +(defcustom flymake-no-changes-timeout 0.5 + "Time to wait after last change before starting compilation." + :group 'flymake + :type 'number) + +(defcustom flymake-gui-warnings-enabled t + "Enables/disables GUI warnings." + :group 'flymake + :type 'boolean) +(make-obsolete-variable 'flymake-gui-warnings-enabled + "it no longer has any effect." "26.1") + +(defcustom flymake-start-syntax-check-on-find-file t + "Start syntax check on find file." + :group 'flymake + :type 'boolean) + +(defcustom flymake-log-level -1 + "Logging level, only messages with level lower or equal will be logged. +-1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG" + :group 'flymake + :type 'integer) + +(defcustom flymake-backends '() + "Ordered list of backends providing syntax check information for a buffer. +Value is an alist of conses (PREDICATE . CHECKER). Both PREDICATE +and CHECKER are functions called with a single argument, the +buffer in which `flymake-mode' was enabled. PREDICATE is expected +to (quickly) return t or nil if the buffer can be syntax checked +by CHECKER, which in can performs more morose operations, +possibly asynchronously." + :group 'flymake + :type 'alist) + +(defvar-local flymake-timer nil + "Timer for starting syntax check.") + +(defvar-local flymake-last-change-time nil + "Time of last buffer change.") + +(defvar-local flymake-check-start-time nil + "Time at which syntax check was started.") + +(defvar-local flymake-check-was-interrupted nil + "Non-nil if syntax check was killed by `flymake-compile'.") + +(defvar-local flymake-err-info nil + "Sorted list of line numbers and lists of err info in the form (file, err-text).") + +(defvar-local flymake-new-err-info nil + "Same as `flymake-err-info', effective when a syntax check is in progress.") + +(defun flymake-log (level text &rest args) + "Log a message at level LEVEL. +If LEVEL is higher than `flymake-log-level', the message is +ignored. Otherwise, it is printed using `message'. +TEXT is a format control string, and the remaining arguments ARGS +are the string substitutions (see the function `format')." + (if (<= level flymake-log-level) + (let* ((msg (apply #'format-message text args))) + (message "%s" msg)))) + +(defun flymake-ins-after (list pos val) + "Insert VAL into LIST after position POS. +POS counts from zero." + (let ((tmp (copy-sequence list))) + (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp))) + tmp)) + +(defun flymake-set-at (list pos val) + "Set VAL at position POS in LIST. +POS counts from zero." + (let ((tmp (copy-sequence list))) + (setcar (nthcdr pos tmp) val) + tmp)) + +(defun flymake-er-make-er (line-no line-err-info-list) + (list line-no line-err-info-list)) + +(defun flymake-er-get-line (err-info) + (nth 0 err-info)) + +(defun flymake-er-get-line-err-info-list (err-info) + (nth 1 err-info)) + +(cl-defstruct (flymake-ler + (:constructor nil) + (:constructor flymake-ler-make-ler (file line type text &optional full-file))) + file line type text full-file) + +(defun flymake-ler-set-file (line-err-info file) + (flymake-ler-make-ler file + (flymake-ler-line line-err-info) + (flymake-ler-type line-err-info) + (flymake-ler-text line-err-info) + (flymake-ler-full-file line-err-info))) + +(defun flymake-ler-set-full-file (line-err-info full-file) + (flymake-ler-make-ler (flymake-ler-file line-err-info) + (flymake-ler-line line-err-info) + (flymake-ler-type line-err-info) + (flymake-ler-text line-err-info) + full-file)) + +(defun flymake-ler-set-line (line-err-info line) + (flymake-ler-make-ler (flymake-ler-file line-err-info) + line + (flymake-ler-type line-err-info) + (flymake-ler-text line-err-info) + (flymake-ler-full-file line-err-info))) + +(defun flymake-get-line-err-count (line-err-info-list type) + "Return number of errors of specified TYPE. +Value of TYPE is either \"e\" or \"w\"." + (let* ((idx 0) + (count (length line-err-info-list)) + (err-count 0)) + + (while (< idx count) + (when (equal type (flymake-ler-type (nth idx line-err-info-list))) + (setq err-count (1+ err-count))) + (setq idx (1+ idx))) + err-count)) + +(defun flymake-get-err-count (err-info-list type) + "Return number of errors of specified TYPE for ERR-INFO-LIST." + (let* ((idx 0) + (count (length err-info-list)) + (err-count 0)) + (while (< idx count) + (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type))) + (setq idx (1+ idx))) + err-count)) + +(defun flymake-highlight-err-lines (err-info-list) + "Highlight error lines in BUFFER using info from ERR-INFO-LIST." + (save-excursion + (dolist (err err-info-list) + (flymake-highlight-line (car err) (nth 1 err))))) + +(defun flymake-overlay-p (ov) + "Determine whether overlay OV was created by flymake." + (and (overlayp ov) (overlay-get ov 'flymake-overlay))) + +(defun flymake-make-overlay (beg end tooltip-text face bitmap) + "Allocate a flymake overlay in range BEG and END." + (when (not (flymake-region-has-flymake-overlays beg end)) + (let ((ov (make-overlay beg end nil t)) + (fringe (and flymake-fringe-indicator-position + (propertize "!" 'display + (cons flymake-fringe-indicator-position + (if (listp bitmap) + bitmap + (list bitmap))))))) + (overlay-put ov 'face face) + (overlay-put ov 'help-echo tooltip-text) + (overlay-put ov 'flymake-overlay t) + (overlay-put ov 'priority 100) + (overlay-put ov 'evaporate t) + (overlay-put ov 'before-string fringe) + ;;+(flymake-log 3 "created overlay %s" ov) + ov) + (flymake-log 3 "created an overlay at (%d-%d)" beg end))) + +(defun flymake-delete-own-overlays () + "Delete all flymake overlays in BUFFER." + (dolist (ol (overlays-in (point-min) (point-max))) + (when (flymake-overlay-p ol) + (delete-overlay ol) + ;;+(flymake-log 3 "deleted overlay %s" ol) + ))) + +(defun flymake-region-has-flymake-overlays (beg end) + "Check if region specified by BEG and END has overlay. +Return t if it has at least one flymake overlay, nil if no overlay." + (let ((ov (overlays-in beg end)) + (has-flymake-overlays nil)) + (while (consp ov) + (when (flymake-overlay-p (car ov)) + (setq has-flymake-overlays t)) + (setq ov (cdr ov))) + has-flymake-overlays)) + +(defface flymake-errline + '((((supports :underline (:style wave))) + :underline (:style wave :color "Red1")) + (t + :inherit error)) + "Face used for marking error lines." + :version "24.4" + :group 'flymake) + +(defface flymake-warnline + '((((supports :underline (:style wave))) + :underline (:style wave :color "DarkOrange")) + (t + :inherit warning)) + "Face used for marking warning lines." + :version "24.4" + :group 'flymake) + +(defun flymake-highlight-line (line-no line-err-info-list) + "Highlight line LINE-NO in current buffer. +Perhaps use text from LINE-ERR-INFO-LIST to enhance highlighting." + (goto-char (point-min)) + (forward-line (1- line-no)) + (pcase-let* ((beg (progn (back-to-indentation) (point))) + (end (progn + (end-of-line) + (skip-chars-backward " \t\f\t\n" beg) + (if (eq (point) beg) + (line-beginning-position 2) + (point)))) + (tooltip-text (mapconcat #'flymake-ler-text line-err-info-list "\n")) + (`(,face ,bitmap) + (if (> (flymake-get-line-err-count line-err-info-list "e") 0) + (list 'flymake-errline flymake-error-bitmap) + (list 'flymake-warnline flymake-warning-bitmap)))) + (flymake-make-overlay beg end tooltip-text face bitmap))) + +(defun flymake-find-err-info (err-info-list line-no) + "Find (line-err-info-list pos) for specified LINE-NO." + (if err-info-list + (let* ((line-err-info-list nil) + (pos 0) + (count (length err-info-list))) + + (while (and (< pos count) (< (car (nth pos err-info-list)) line-no)) + (setq pos (1+ pos))) + (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no)) + (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list)))) + (list line-err-info-list pos)) + '(nil 0))) + +(defun flymake-line-err-info-is-less-or-equal (line-one line-two) + (or (string< (flymake-ler-type line-one) (flymake-ler-type line-two)) + (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two)) + (not (flymake-ler-file line-one)) (flymake-ler-file line-two)) + (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two)) + (or (and (flymake-ler-file line-one) (flymake-ler-file line-two)) + (and (not (flymake-ler-file line-one)) (not (flymake-ler-file line-two))))))) + +(defun flymake-add-line-err-info (line-err-info-list line-err-info) + "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO. +For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'. +The new element is inserted in the proper position, according to +the predicate `flymake-line-err-info-is-less-or-equal'. +The updated value of LINE-ERR-INFO-LIST is returned." + (if (not line-err-info-list) + (list line-err-info) + (let* ((count (length line-err-info-list)) + (idx 0)) + (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info)) + (setq idx (1+ idx))) + (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list))) + (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info)))) + line-err-info-list))) + +(defun flymake-add-err-info (err-info-list line-err-info) + "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order. +Returns the updated value of ERR-INFO-LIST. +For the format of ERR-INFO-LIST, see `flymake-err-info'. +For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'." + (let* ((line-no (if (flymake-ler-file line-err-info) 1 (flymake-ler-line line-err-info))) + (info-and-pos (flymake-find-err-info err-info-list line-no)) + (exists (car info-and-pos)) + (pos (nth 1 info-and-pos)) + (line-err-info-list nil) + (err-info nil)) + + (if exists + (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list))))) + (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info)) + + (setq err-info (flymake-er-make-er line-no line-err-info-list)) + (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info))) + ((equal 0 pos) (setq err-info-list (cons err-info err-info-list))) + (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info)))) + err-info-list)) + +(defvar-local flymake-is-running nil + "If t, flymake syntax check process is running for the current buffer.") + +(defun flymake-on-timer-event (buffer) + "Start a syntax check for buffer BUFFER if necessary." + (when (buffer-live-p buffer) + (with-current-buffer buffer + (when (and (not flymake-is-running) + flymake-last-change-time + (> (- (float-time) flymake-last-change-time) + flymake-no-changes-timeout)) + + (setq flymake-last-change-time nil) + (flymake-log 3 "starting syntax check as more than 1 second passed since last change") + (flymake--start-syntax-check))))) + +(define-obsolete-function-alias 'flymake-display-err-menu-for-current-line + 'flymake-popup-current-error-menu "24.4") + +(defun flymake-popup-current-error-menu (&optional event) + "Pop up a menu with errors/warnings for current line." + (interactive (list last-nonmenu-event)) + (let* ((line-no (line-number-at-pos)) + (errors (or (car (flymake-find-err-info flymake-err-info line-no)) + (user-error "No errors for current line"))) + (menu (mapcar (lambda (x) + (if (flymake-ler-file x) + (cons (format "%s - %s(%d)" + (flymake-ler-text x) + (flymake-ler-file x) + (flymake-ler-line x)) + x) + (list (flymake-ler-text x)))) + errors)) + (event (if (mouse-event-p event) + event + (list 'mouse-1 (posn-at-point)))) + (title (format "Line %d: %d error(s), %d warning(s)" + line-no + (flymake-get-line-err-count errors "e") + (flymake-get-line-err-count errors "w"))) + (choice (x-popup-menu event (list title (cons "" menu))))) + (flymake-log 3 "choice=%s" choice) + (when choice + (flymake-goto-file-and-line (flymake-ler-full-file choice) + (flymake-ler-line choice))))) + +(defun flymake-goto-file-and-line (file line) + "Try to get buffer for FILE and goto line LINE in it." + (if (not (file-exists-p file)) + (flymake-log 1 "File %s does not exist" file) + (find-file file) + (goto-char (point-min)) + (forward-line (1- line)))) + +;; flymake minor mode declarations +(defvar-local flymake-mode-line nil) +(defvar-local flymake-mode-line-e-w nil) +(defvar-local flymake-mode-line-status nil) + +(defun flymake-report-status (e-w &optional status) + "Show status in mode line." + (when e-w + (setq flymake-mode-line-e-w e-w)) + (when status + (setq flymake-mode-line-status status)) + (let* ((mode-line " Flymake")) + (when (> (length flymake-mode-line-e-w) 0) + (setq mode-line (concat mode-line ":" flymake-mode-line-e-w))) + (setq mode-line (concat mode-line flymake-mode-line-status)) + (setq flymake-mode-line mode-line) + (force-mode-line-update))) + +;; Nothing in flymake uses this at all any more, so this is just for +;; third-party compatibility. +(define-obsolete-function-alias 'flymake-display-warning 'message-box "26.1") + +(defun flymake-report-fatal-status (status warning) + "Display a warning and switch flymake mode off." + ;; This first message was always shown by default, and flymake-log + ;; does nothing by default, hence the use of message. + ;; Another option is display-warning. + (if (< flymake-log-level 0) + (message "Flymake: %s. Flymake will be switched OFF" warning)) + (flymake-mode 0) + (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s" + (buffer-name) status warning)) + +(defvar-local flymake--backend nil + "The currently active backend selected by `flymake-mode'") + +(defun flymake--can-syntax-check-buffer (buffer) + (let ((all flymake-backends) + (candidate)) + (catch 'done + (while (setq candidate (pop all)) + (when (with-current-buffer buffer (funcall (car candidate))) + (throw 'done (cdr candidate))))))) + +(defun flymake--start-syntax-check () + (funcall flymake--backend)) + +;;;###autoload +(define-minor-mode flymake-mode nil + :group 'flymake :lighter flymake-mode-line + (cond + + ;; Turning the mode ON. + (flymake-mode + (let* ((backend (flymake--can-syntax-check-buffer (current-buffer)))) + (cond + ((not backend) + (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name))) + (t + (setq flymake--backend backend) + + (add-hook 'after-change-functions 'flymake-after-change-function nil t) + (add-hook 'after-save-hook 'flymake-after-save-hook nil t) + (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t) + ;;+(add-hook 'find-file-hook 'flymake-find-file-hook) + + (flymake-report-status "" "") + + (setq flymake-timer + (run-at-time nil 1 'flymake-on-timer-event (current-buffer))) + + (when (and flymake-start-syntax-check-on-find-file + ;; Since we write temp files in current dir, there's no point + ;; trying if the directory is read-only (bug#8954). + (file-writable-p (file-name-directory buffer-file-name))) + (with-demoted-errors + (flymake--start-syntax-check))))) + ) + ) + + ;; Turning the mode OFF. + (t + (setq flymake--backend nil) + + (remove-hook 'after-change-functions 'flymake-after-change-function t) + (remove-hook 'after-save-hook 'flymake-after-save-hook t) + (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t) + ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t) + + (flymake-delete-own-overlays) + + (when flymake-timer + (cancel-timer flymake-timer) + (setq flymake-timer nil)) + + (setq flymake-is-running nil)))) + +;; disabling flymake-mode is safe, enabling - not necessarily so +(put 'flymake-mode 'safe-local-variable 'null) + +;;;###autoload +(defun flymake-mode-on () + "Turn flymake mode on." + (flymake-mode 1) + (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name))) + +;;;###autoload +(defun flymake-mode-off () + "Turn flymake mode off." + (flymake-mode 0) + (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name))) + +(defun flymake-after-change-function (start stop _len) + "Start syntax check for current buffer if it isn't already running." + ;;+(flymake-log 0 "setting change time to %s" (float-time)) + (let((new-text (buffer-substring start stop))) + (when (and flymake-start-syntax-check-on-newline (equal new-text "\n")) + (flymake-log 3 "starting syntax check as new-line has been seen") + (flymake--start-syntax-check)) + (setq flymake-last-change-time (float-time)))) + +(defun flymake-after-save-hook () + (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved? + (progn + (flymake-log 3 "starting syntax check as buffer was saved") + (flymake--start-syntax-check)))) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???) + +(defun flymake-kill-buffer-hook () + (when flymake-timer + (cancel-timer flymake-timer) + (setq flymake-timer nil))) + +;;;###autoload +(defun flymake-find-file-hook () + ;;+(when flymake-start-syntax-check-on-find-file + ;;+ (flymake-log 3 "starting syntax check on file open") + ;;+ (flymake--start-syntax-check) + ;;+) + (when (and (not (local-variable-p 'flymake-mode (current-buffer))) + (flymake--can-syntax-check-buffer (current-buffer))) + (flymake-mode) + (flymake-log 3 "automatically turned ON flymake mode"))) + +(defun flymake-get-first-err-line-no (err-info-list) + "Return first line with error." + (when err-info-list + (flymake-er-get-line (car err-info-list)))) + +(defun flymake-get-last-err-line-no (err-info-list) + "Return last line with error." + (when err-info-list + (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list)))) + +(defun flymake-get-next-err-line-no (err-info-list line-no) + "Return next line with error." + (when err-info-list + (let* ((count (length err-info-list)) + (idx 0)) + (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list)))) + (setq idx (1+ idx))) + (if (< idx count) + (flymake-er-get-line (nth idx err-info-list)))))) + +(defun flymake-get-prev-err-line-no (err-info-list line-no) + "Return previous line with error." + (when err-info-list + (let* ((count (length err-info-list))) + (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list)))) + (setq count (1- count))) + (if (> count 0) + (flymake-er-get-line (nth (1- count) err-info-list)))))) + +(defun flymake-skip-whitespace () + "Move forward until non-whitespace is reached." + (while (looking-at "[ \t]") + (forward-char))) + +(defun flymake-goto-line (line-no) + "Go to line LINE-NO, then skip whitespace." + (goto-char (point-min)) + (forward-line (1- line-no)) + (flymake-skip-whitespace)) + +(defun flymake-goto-next-error () + "Go to next error in err ring." + (interactive) + (let ((line-no (flymake-get-next-err-line-no flymake-err-info (line-number-at-pos)))) + (when (not line-no) + (setq line-no (flymake-get-first-err-line-no flymake-err-info)) + (flymake-log 1 "passed end of file")) + (if line-no + (flymake-goto-line line-no) + (flymake-log 1 "no errors in current buffer")))) + +(defun flymake-goto-prev-error () + "Go to previous error in err ring." + (interactive) + (let ((line-no (flymake-get-prev-err-line-no flymake-err-info (line-number-at-pos)))) + (when (not line-no) + (setq line-no (flymake-get-last-err-line-no flymake-err-info)) + (flymake-log 1 "passed beginning of file")) + (if line-no + (flymake-goto-line line-no) + (flymake-log 1 "no errors in current buffer")))) + +(defun flymake-patch-err-text (string) + (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string) + (match-string 1 string) + string)) + +(provide 'flymake-ui) +;;; flymake-ui.el ends here diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index 866116fbecd..059bce95eed 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -24,1629 +24,18 @@ ;;; Commentary: ;; -;; Flymake is a minor Emacs mode performing on-the-fly syntax checks -;; using the external syntax check tool (for C/C++ this is usually the -;; compiler). - -;;; Bugs/todo: - -;; - Only uses "Makefile", not "makefile" or "GNUmakefile" -;; (from http://bugs.debian.org/337339). +;; Flymake is a minor Emacs mode performing on-the-fly syntax checks. +;; +;; It collects diagnostic information for multiple sources and +;; visually annotates the relevant lines in the buffer. +;; +;; This file is just a stub for that loads the UI and backends, which +;; could also be loaded separately. ;;; Code: -(eval-when-compile (require 'cl-lib)) - -(defgroup flymake nil - "Universal on-the-fly syntax checker." - :version "23.1" - :link '(custom-manual "(flymake) Top") - :group 'tools) - -(defcustom flymake-error-bitmap '(exclamation-mark error) - "Bitmap (a symbol) used in the fringe for indicating errors. -The value may also be a list of two elements where the second -element specifies the face for the bitmap. For possible bitmap -symbols, see `fringe-bitmaps'. See also `flymake-warning-bitmap'. - -The option `flymake-fringe-indicator-position' controls how and where -this is used." - :group 'flymake - :version "24.3" - :type '(choice (symbol :tag "Bitmap") - (list :tag "Bitmap and face" - (symbol :tag "Bitmap") - (face :tag "Face")))) - -(defcustom flymake-warning-bitmap 'question-mark - "Bitmap (a symbol) used in the fringe for indicating warnings. -The value may also be a list of two elements where the second -element specifies the face for the bitmap. For possible bitmap -symbols, see `fringe-bitmaps'. See also `flymake-error-bitmap'. - -The option `flymake-fringe-indicator-position' controls how and where -this is used." - :group 'flymake - :version "24.3" - :type '(choice (symbol :tag "Bitmap") - (list :tag "Bitmap and face" - (symbol :tag "Bitmap") - (face :tag "Face")))) - -(defcustom flymake-fringe-indicator-position 'left-fringe - "The position to put flymake fringe indicator. -The value can be nil (do not use indicators), `left-fringe' or `right-fringe'. -See `flymake-error-bitmap' and `flymake-warning-bitmap'." - :group 'flymake - :version "24.3" - :type '(choice (const left-fringe) - (const right-fringe) - (const :tag "No fringe indicators" nil))) - -(defcustom flymake-compilation-prevents-syntax-check t - "If non-nil, don't start syntax check if compilation is running." - :group 'flymake - :type 'boolean) - -(defcustom flymake-start-syntax-check-on-newline t - "Start syntax check if newline char was added/removed from the buffer." - :group 'flymake - :type 'boolean) - -(defcustom flymake-no-changes-timeout 0.5 - "Time to wait after last change before starting compilation." - :group 'flymake - :type 'number) - -(defcustom flymake-gui-warnings-enabled t - "Enables/disables GUI warnings." - :group 'flymake - :type 'boolean) -(make-obsolete-variable 'flymake-gui-warnings-enabled - "it no longer has any effect." "26.1") - -(defcustom flymake-start-syntax-check-on-find-file t - "Start syntax check on find file." - :group 'flymake - :type 'boolean) - -(defcustom flymake-log-level -1 - "Logging level, only messages with level lower or equal will be logged. --1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG" - :group 'flymake - :type 'integer) - -(defcustom flymake-xml-program - (if (executable-find "xmlstarlet") "xmlstarlet" "xml") - "Program to use for XML validation." - :type 'file - :group 'flymake - :version "24.4") - -(defcustom flymake-master-file-dirs '("." "./src" "./UnitTest") - "Dirs where to look for master files." - :group 'flymake - :type '(repeat (string))) - -(defcustom flymake-master-file-count-limit 32 - "Max number of master files to check." - :group 'flymake - :type 'integer) - -(defcustom flymake-allowed-file-name-masks - '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init) - ("\\.xml\\'" flymake-xml-init) - ("\\.html?\\'" flymake-xml-init) - ("\\.cs\\'" flymake-simple-make-init) - ("\\.p[ml]\\'" flymake-perl-init) - ("\\.php[345]?\\'" flymake-php-init) - ("\\.h\\'" flymake-master-make-header-init flymake-master-cleanup) - ("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup) - ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup) - ("\\.tex\\'" flymake-simple-tex-init) - ("\\.idl\\'" flymake-simple-make-init) - ;; ("\\.cpp\\'" 1) - ;; ("\\.java\\'" 3) - ;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'") - ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2)) - ;; ("\\.idl\\'" 1) - ;; ("\\.odl\\'" 1) - ;; ("[0-9]+\\.tex\\'" 2 ("\\.tex\\'") - ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 )) - ;; ("\\.tex\\'" 1) - ) - "Files syntax checking is allowed for. -This is an alist with elements of the form: - REGEXP INIT [CLEANUP [NAME]] -REGEXP is a regular expression that matches a file name. -INIT is the init function to use, missing means disable `flymake-mode'. -CLEANUP is the cleanup function to use, default `flymake-simple-cleanup'. -NAME is the file name function to use, default `flymake-get-real-file-name'." - :group 'flymake - :type '(alist :key-type (regexp :tag "File regexp") - :value-type - (list :tag "Handler functions" - (choice :tag "Init function" - (const :tag "disable" nil) - function) - (choice :tag "Cleanup function" - (const :tag "flymake-simple-cleanup" nil) - function) - (choice :tag "Name function" - (const :tag "flymake-get-real-file-name" nil) - function)))) - -(defvar-local flymake-is-running nil - "If t, flymake syntax check process is running for the current buffer.") - -(defvar-local flymake-timer nil - "Timer for starting syntax check.") - -(defvar-local flymake-last-change-time nil - "Time of last buffer change.") - -(defvar-local flymake-check-start-time nil - "Time at which syntax check was started.") - -(defvar-local flymake-check-was-interrupted nil - "Non-nil if syntax check was killed by `flymake-compile'.") - -(defvar-local flymake-err-info nil - "Sorted list of line numbers and lists of err info in the form (file, err-text).") - -(defvar-local flymake-new-err-info nil - "Same as `flymake-err-info', effective when a syntax check is in progress.") - -(defun flymake-log (level text &rest args) - "Log a message at level LEVEL. -If LEVEL is higher than `flymake-log-level', the message is -ignored. Otherwise, it is printed using `message'. -TEXT is a format control string, and the remaining arguments ARGS -are the string substitutions (see the function `format')." - (if (<= level flymake-log-level) - (let* ((msg (apply #'format-message text args))) - (message "%s" msg)))) - -(defun flymake-ins-after (list pos val) - "Insert VAL into LIST after position POS. -POS counts from zero." - (let ((tmp (copy-sequence list))) - (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp))) - tmp)) - -(defun flymake-set-at (list pos val) - "Set VAL at position POS in LIST. -POS counts from zero." - (let ((tmp (copy-sequence list))) - (setcar (nthcdr pos tmp) val) - tmp)) - -(defvar flymake-processes nil - "List of currently active flymake processes.") - -(defvar-local flymake-output-residual nil) - -(defun flymake-get-file-name-mode-and-masks (file-name) - "Return the corresponding entry from `flymake-allowed-file-name-masks'." - (unless (stringp file-name) - (error "Invalid file-name")) - (let ((fnm flymake-allowed-file-name-masks) - (mode-and-masks nil)) - (while (and (not mode-and-masks) fnm) - (let ((item (pop fnm))) - (when (string-match (car item) file-name) - (setq mode-and-masks item)))) ; (cdr item) may be nil - (setq mode-and-masks (cdr mode-and-masks)) - (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks)) - mode-and-masks)) - -(defun flymake-can-syntax-check-file (file-name) - "Determine whether we can syntax check FILE-NAME. -Return nil if we cannot, non-nil if we can." - (if (flymake-get-init-function file-name) t nil)) - -(defun flymake-get-init-function (file-name) - "Return init function to be used for the file." - (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name)))) - ;;(flymake-log 0 "calling %s" init-f) - ;;(funcall init-f (current-buffer)) - init-f)) - -(defun flymake-get-cleanup-function (file-name) - "Return cleanup function to be used for the file." - (or (nth 1 (flymake-get-file-name-mode-and-masks file-name)) - 'flymake-simple-cleanup)) - -(defun flymake-get-real-file-name-function (file-name) - (or (nth 2 (flymake-get-file-name-mode-and-masks file-name)) - 'flymake-get-real-file-name)) - -(defvar flymake-find-buildfile-cache (make-hash-table :test #'equal)) - -(defun flymake-get-buildfile-from-cache (dir-name) - "Look up DIR-NAME in cache and return its associated value. -If DIR-NAME is not found, return nil." - (gethash dir-name flymake-find-buildfile-cache)) - -(defun flymake-add-buildfile-to-cache (dir-name buildfile) - "Associate DIR-NAME with BUILDFILE in the buildfile cache." - (puthash dir-name buildfile flymake-find-buildfile-cache)) - -(defun flymake-clear-buildfile-cache () - "Clear the buildfile cache." - (clrhash flymake-find-buildfile-cache)) - -(defun flymake-find-buildfile (buildfile-name source-dir-name) - "Find buildfile starting from current directory. -Buildfile includes Makefile, build.xml etc. -Return its file name if found, or nil if not found." - (or (flymake-get-buildfile-from-cache source-dir-name) - (let* ((file (locate-dominating-file source-dir-name buildfile-name))) - (if file - (progn - (flymake-log 3 "found buildfile at %s" file) - (flymake-add-buildfile-to-cache source-dir-name file) - file) - (progn - (flymake-log 3 "buildfile for %s not found" source-dir-name) - nil))))) - -(defun flymake-fix-file-name (name) - "Replace all occurrences of `\\' with `/'." - (when name - (setq name (expand-file-name name)) - (setq name (abbreviate-file-name name)) - (setq name (directory-file-name name)) - name)) - -(defun flymake-same-files (file-name-one file-name-two) - "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file. -Return t if so, nil if not." - (equal (flymake-fix-file-name file-name-one) - (flymake-fix-file-name file-name-two))) - -;; This is bound dynamically to pass a parameter to a sort predicate below -(defvar flymake-included-file-name) - -(defun flymake-find-possible-master-files (file-name master-file-dirs masks) - "Find (by name and location) all possible master files. - -Name is specified by FILE-NAME and location is specified by -MASTER-FILE-DIRS. Master files include .cpp and .c for .h. -Files are searched for starting from the .h directory and max -max-level parent dirs. File contents are not checked." - (let* ((dirs master-file-dirs) - (files nil) - (done nil)) - - (while (and (not done) dirs) - (let* ((dir (expand-file-name (car dirs) (file-name-directory file-name))) - (masks masks)) - (while (and (file-exists-p dir) (not done) masks) - (let* ((mask (car masks)) - (dir-files (directory-files dir t mask))) - - (flymake-log 3 "dir %s, %d file(s) for mask %s" - dir (length dir-files) mask) - (while (and (not done) dir-files) - (when (not (file-directory-p (car dir-files))) - (setq files (cons (car dir-files) files)) - (when (>= (length files) flymake-master-file-count-limit) - (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit) - (setq done t))) - (setq dir-files (cdr dir-files)))) - (setq masks (cdr masks)))) - (setq dirs (cdr dirs))) - (when files - (let ((flymake-included-file-name (file-name-nondirectory file-name))) - (setq files (sort files 'flymake-master-file-compare)))) - (flymake-log 3 "found %d possible master file(s)" (length files)) - files)) - -(defun flymake-master-file-compare (file-one file-two) - "Compare two files specified by FILE-ONE and FILE-TWO. -This function is used in sort to move most possible file names -to the beginning of the list (File.h -> File.cpp moved to top)." - (and (equal (file-name-sans-extension flymake-included-file-name) - (file-name-base file-one)) - (not (equal file-one file-two)))) - -(defvar flymake-check-file-limit 8192 - "Maximum number of chars to look at when checking possible master file. -Nil means search the entire file.") - -(defun flymake-check-patch-master-file-buffer - (master-file-temp-buffer - master-file-name patched-master-file-name - source-file-name patched-source-file-name - include-dirs regexp) - "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME. -If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME -instead of SOURCE-FILE-NAME. - -For example, foo.cpp is a master file if it includes foo.h. - -When a buffer for MASTER-FILE-NAME exists, use it as a source -instead of reading master file from disk." - (let* ((source-file-nondir (file-name-nondirectory source-file-name)) - (source-file-extension (file-name-extension source-file-nondir)) - (source-file-nonext (file-name-sans-extension source-file-nondir)) - (found nil) - (inc-name nil) - (search-limit flymake-check-file-limit)) - (setq regexp - (format regexp ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\"" - ;; Hack for tex files, where \include often excludes .tex. - ;; Maybe this is safe generally. - (if (and (> (length source-file-extension) 1) - (string-equal source-file-extension "tex")) - (format "%s\\(?:\\.%s\\)?" - (regexp-quote source-file-nonext) - (regexp-quote source-file-extension)) - (regexp-quote source-file-nondir)))) - (unwind-protect - (with-current-buffer master-file-temp-buffer - (if (or (not search-limit) - (> search-limit (point-max))) - (setq search-limit (point-max))) - (flymake-log 3 "checking %s against regexp %s" - master-file-name regexp) - (goto-char (point-min)) - (while (and (< (point) search-limit) - (re-search-forward regexp search-limit t)) - (let ((match-beg (match-beginning 1)) - (match-end (match-end 1))) - - (flymake-log 3 "found possible match for %s" source-file-nondir) - (setq inc-name (match-string 1)) - (and (> (length source-file-extension) 1) - (string-equal source-file-extension "tex") - (not (string-match (format "\\.%s\\'" source-file-extension) - inc-name)) - (setq inc-name (concat inc-name "." source-file-extension))) - (when (eq t (compare-strings - source-file-nondir nil nil - inc-name (- (length inc-name) - (length source-file-nondir)) nil)) - (flymake-log 3 "inc-name=%s" inc-name) - (when (flymake-check-include source-file-name inc-name - include-dirs) - (setq found t) - ;; replace-match is not used here as it fails in - ;; XEmacs with 'last match not a buffer' error as - ;; check-includes calls replace-in-string - (flymake-replace-region - match-beg match-end - (file-name-nondirectory patched-source-file-name)))) - (forward-line 1))) - (when found - (flymake-save-buffer-in-file patched-master-file-name))) - ;;+(flymake-log 3 "killing buffer %s" - ;; (buffer-name master-file-temp-buffer)) - (kill-buffer master-file-temp-buffer)) - ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found) - (when found - (flymake-log 2 "found master file %s" master-file-name)) - found)) - -;;; XXX: remove -(defun flymake-replace-region (beg end rep) - "Replace text in BUFFER in region (BEG END) with REP." - (save-excursion - (goto-char end) - ;; Insert before deleting, so as to better preserve markers's positions. - (insert rep) - (delete-region beg end))) - -(defun flymake-read-file-to-temp-buffer (file-name) - "Insert contents of FILE-NAME into newly created temp buffer." - (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name)))))) - (with-current-buffer temp-buffer - (insert-file-contents file-name)) - temp-buffer)) - -(defun flymake-copy-buffer-to-temp-buffer (buffer) - "Copy contents of BUFFER into newly created temp buffer." - (with-current-buffer - (get-buffer-create (generate-new-buffer-name - (concat "flymake:" (buffer-name buffer)))) - (insert-buffer-substring buffer) - (current-buffer))) - -(defun flymake-check-include (source-file-name inc-name include-dirs) - "Check if SOURCE-FILE-NAME can be found in include path. -Return t if it can be found via include path using INC-NAME." - (if (file-name-absolute-p inc-name) - (flymake-same-files source-file-name inc-name) - (while (and include-dirs - (not (flymake-same-files - source-file-name - (concat (file-name-directory source-file-name) - "/" (car include-dirs) - "/" inc-name)))) - (setq include-dirs (cdr include-dirs))) - include-dirs)) - -(defun flymake-find-buffer-for-file (file-name) - "Check if there exists a buffer visiting FILE-NAME. -Return t if so, nil if not." - (let ((buffer-name (get-file-buffer file-name))) - (if buffer-name - (get-buffer buffer-name)))) - -(defun flymake-create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp) - "Save SOURCE-FILE-NAME with a different name. -Find master file, patch and save it." - (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks)) - (master-file-count (length possible-master-files)) - (idx 0) - (temp-buffer nil) - (master-file-name nil) - (patched-master-file-name nil) - (found nil)) - - (while (and (not found) (< idx master-file-count)) - (setq master-file-name (nth idx possible-master-files)) - (setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master")) - (if (flymake-find-buffer-for-file master-file-name) - (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name))) - (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name))) - (setq found - (flymake-check-patch-master-file-buffer - temp-buffer - master-file-name - patched-master-file-name - source-file-name - patched-source-file-name - (funcall get-incl-dirs-f (file-name-directory master-file-name)) - include-regexp)) - (setq idx (1+ idx))) - (if found - (list master-file-name patched-master-file-name) - (progn - (flymake-log 3 "none of %d master file(s) checked includes %s" master-file-count - (file-name-nondirectory source-file-name)) - nil)))) - -(defun flymake-save-buffer-in-file (file-name) - "Save the entire buffer contents into file FILE-NAME. -Create parent directories as needed." - (make-directory (file-name-directory file-name) 1) - (write-region nil nil file-name nil 566) - (flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name)) - -(defun flymake-process-filter (process output) - "Parse OUTPUT and highlight error lines. -It's flymake process filter." - (let ((source-buffer (process-buffer process))) - - (flymake-log 3 "received %d byte(s) of output from process %d" - (length output) (process-id process)) - (when (buffer-live-p source-buffer) - (with-current-buffer source-buffer - (flymake-parse-output-and-residual output))))) - -(defun flymake-process-sentinel (process _event) - "Sentinel for syntax check buffers." - (when (memq (process-status process) '(signal exit)) - (let* ((exit-status (process-exit-status process)) - (command (process-command process)) - (source-buffer (process-buffer process)) - (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer)))) - - (flymake-log 2 "process %d exited with code %d" - (process-id process) exit-status) - (condition-case err - (progn - (flymake-log 3 "cleaning up using %s" cleanup-f) - (when (buffer-live-p source-buffer) - (with-current-buffer source-buffer - (funcall cleanup-f))) - - (delete-process process) - (setq flymake-processes (delq process flymake-processes)) - - (when (buffer-live-p source-buffer) - (with-current-buffer source-buffer - - (flymake-parse-residual) - (flymake-post-syntax-check exit-status command) - (setq flymake-is-running nil)))) - (error - (let ((err-str (format "Error in process sentinel for buffer %s: %s" - source-buffer (error-message-string err)))) - (flymake-log 0 err-str) - (with-current-buffer source-buffer - (setq flymake-is-running nil)))))))) - -(defun flymake-post-syntax-check (exit-status command) - (save-restriction - (widen) - (setq flymake-err-info flymake-new-err-info) - (setq flymake-new-err-info nil) - (setq flymake-err-info - (flymake-fix-line-numbers - flymake-err-info 1 (count-lines (point-min) (point-max)))) - (flymake-delete-own-overlays) - (flymake-highlight-err-lines flymake-err-info) - (let (err-count warn-count) - (setq err-count (flymake-get-err-count flymake-err-info "e")) - (setq warn-count (flymake-get-err-count flymake-err-info "w")) - (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)" - (buffer-name) err-count warn-count - (- (float-time) flymake-check-start-time)) - (setq flymake-check-start-time nil) - - (if (and (equal 0 err-count) (equal 0 warn-count)) - (if (equal 0 exit-status) - (flymake-report-status "" "") ; PASSED - (if (not flymake-check-was-interrupted) - (flymake-report-fatal-status "CFGERR" - (format "Configuration error has occurred while running %s" command)) - (flymake-report-status nil ""))) ; "STOPPED" - (flymake-report-status (format "%d/%d" err-count warn-count) ""))))) - -(defun flymake-parse-output-and-residual (output) - "Split OUTPUT into lines, merge in residual if necessary." - (let* ((buffer-residual flymake-output-residual) - (total-output (if buffer-residual (concat buffer-residual output) output)) - (lines-and-residual (flymake-split-output total-output)) - (lines (nth 0 lines-and-residual)) - (new-residual (nth 1 lines-and-residual))) - (setq flymake-output-residual new-residual) - (setq flymake-new-err-info - (flymake-parse-err-lines - flymake-new-err-info lines)))) - -(defun flymake-parse-residual () - "Parse residual if it's non empty." - (when flymake-output-residual - (setq flymake-new-err-info - (flymake-parse-err-lines - flymake-new-err-info - (list flymake-output-residual))) - (setq flymake-output-residual nil))) - -(defun flymake-er-make-er (line-no line-err-info-list) - (list line-no line-err-info-list)) - -(defun flymake-er-get-line (err-info) - (nth 0 err-info)) - -(defun flymake-er-get-line-err-info-list (err-info) - (nth 1 err-info)) - -(cl-defstruct (flymake-ler - (:constructor nil) - (:constructor flymake-ler-make-ler (file line type text &optional full-file))) - file line type text full-file) - -(defun flymake-ler-set-file (line-err-info file) - (flymake-ler-make-ler file - (flymake-ler-line line-err-info) - (flymake-ler-type line-err-info) - (flymake-ler-text line-err-info) - (flymake-ler-full-file line-err-info))) - -(defun flymake-ler-set-full-file (line-err-info full-file) - (flymake-ler-make-ler (flymake-ler-file line-err-info) - (flymake-ler-line line-err-info) - (flymake-ler-type line-err-info) - (flymake-ler-text line-err-info) - full-file)) - -(defun flymake-ler-set-line (line-err-info line) - (flymake-ler-make-ler (flymake-ler-file line-err-info) - line - (flymake-ler-type line-err-info) - (flymake-ler-text line-err-info) - (flymake-ler-full-file line-err-info))) - -(defun flymake-get-line-err-count (line-err-info-list type) - "Return number of errors of specified TYPE. -Value of TYPE is either \"e\" or \"w\"." - (let* ((idx 0) - (count (length line-err-info-list)) - (err-count 0)) - - (while (< idx count) - (when (equal type (flymake-ler-type (nth idx line-err-info-list))) - (setq err-count (1+ err-count))) - (setq idx (1+ idx))) - err-count)) - -(defun flymake-get-err-count (err-info-list type) - "Return number of errors of specified TYPE for ERR-INFO-LIST." - (let* ((idx 0) - (count (length err-info-list)) - (err-count 0)) - (while (< idx count) - (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type))) - (setq idx (1+ idx))) - err-count)) - -(defun flymake-fix-line-numbers (err-info-list min-line max-line) - "Replace line numbers with fixed value. -If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE. -If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE. -The reason for this fix is because some compilers might report -line number outside the file being compiled." - (let* ((count (length err-info-list)) - (err-info nil) - (line 0)) - (while (> count 0) - (setq err-info (nth (1- count) err-info-list)) - (setq line (flymake-er-get-line err-info)) - (when (or (< line min-line) (> line max-line)) - (setq line (if (< line min-line) min-line max-line)) - (setq err-info-list (flymake-set-at err-info-list (1- count) - (flymake-er-make-er line - (flymake-er-get-line-err-info-list err-info))))) - (setq count (1- count)))) - err-info-list) - -(defun flymake-highlight-err-lines (err-info-list) - "Highlight error lines in BUFFER using info from ERR-INFO-LIST." - (save-excursion - (dolist (err err-info-list) - (flymake-highlight-line (car err) (nth 1 err))))) - -(defun flymake-overlay-p (ov) - "Determine whether overlay OV was created by flymake." - (and (overlayp ov) (overlay-get ov 'flymake-overlay))) - -(defun flymake-make-overlay (beg end tooltip-text face bitmap) - "Allocate a flymake overlay in range BEG and END." - (when (not (flymake-region-has-flymake-overlays beg end)) - (let ((ov (make-overlay beg end nil t)) - (fringe (and flymake-fringe-indicator-position - (propertize "!" 'display - (cons flymake-fringe-indicator-position - (if (listp bitmap) - bitmap - (list bitmap))))))) - (overlay-put ov 'face face) - (overlay-put ov 'help-echo tooltip-text) - (overlay-put ov 'flymake-overlay t) - (overlay-put ov 'priority 100) - (overlay-put ov 'evaporate t) - (overlay-put ov 'before-string fringe) - ;;+(flymake-log 3 "created overlay %s" ov) - ov) - (flymake-log 3 "created an overlay at (%d-%d)" beg end))) - -(defun flymake-delete-own-overlays () - "Delete all flymake overlays in BUFFER." - (dolist (ol (overlays-in (point-min) (point-max))) - (when (flymake-overlay-p ol) - (delete-overlay ol) - ;;+(flymake-log 3 "deleted overlay %s" ol) - ))) - -(defun flymake-region-has-flymake-overlays (beg end) - "Check if region specified by BEG and END has overlay. -Return t if it has at least one flymake overlay, nil if no overlay." - (let ((ov (overlays-in beg end)) - (has-flymake-overlays nil)) - (while (consp ov) - (when (flymake-overlay-p (car ov)) - (setq has-flymake-overlays t)) - (setq ov (cdr ov))) - has-flymake-overlays)) - -(defface flymake-errline - '((((supports :underline (:style wave))) - :underline (:style wave :color "Red1")) - (t - :inherit error)) - "Face used for marking error lines." - :version "24.4" - :group 'flymake) - -(defface flymake-warnline - '((((supports :underline (:style wave))) - :underline (:style wave :color "DarkOrange")) - (t - :inherit warning)) - "Face used for marking warning lines." - :version "24.4" - :group 'flymake) - -(defun flymake-highlight-line (line-no line-err-info-list) - "Highlight line LINE-NO in current buffer. -Perhaps use text from LINE-ERR-INFO-LIST to enhance highlighting." - (goto-char (point-min)) - (forward-line (1- line-no)) - (pcase-let* ((beg (progn (back-to-indentation) (point))) - (end (progn - (end-of-line) - (skip-chars-backward " \t\f\t\n" beg) - (if (eq (point) beg) - (line-beginning-position 2) - (point)))) - (tooltip-text (mapconcat #'flymake-ler-text line-err-info-list "\n")) - (`(,face ,bitmap) - (if (> (flymake-get-line-err-count line-err-info-list "e") 0) - (list 'flymake-errline flymake-error-bitmap) - (list 'flymake-warnline flymake-warning-bitmap)))) - (flymake-make-overlay beg end tooltip-text face bitmap))) - -(defun flymake-parse-err-lines (err-info-list lines) - "Parse err LINES, store info in ERR-INFO-LIST." - (let* ((count (length lines)) - (idx 0) - (line-err-info nil) - (real-file-name nil) - (source-file-name buffer-file-name) - (get-real-file-name-f (flymake-get-real-file-name-function source-file-name))) - - (while (< idx count) - (setq line-err-info (flymake-parse-line (nth idx lines))) - (when line-err-info - (setq real-file-name (funcall get-real-file-name-f - (flymake-ler-file line-err-info))) - (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name)) - - (when (flymake-same-files real-file-name source-file-name) - (setq line-err-info (flymake-ler-set-file line-err-info nil)) - (setq err-info-list (flymake-add-err-info err-info-list line-err-info)))) - (flymake-log 3 "parsed `%s', %s line-err-info" (nth idx lines) (if line-err-info "got" "no")) - (setq idx (1+ idx))) - err-info-list)) - -(defun flymake-split-output (output) - "Split OUTPUT into lines. -Return last one as residual if it does not end with newline char. -Returns ((LINES) RESIDUAL)." - (when (and output (> (length output) 0)) - (let* ((lines (split-string output "[\n\r]+" t)) - (complete (equal "\n" (char-to-string (aref output (1- (length output)))))) - (residual nil)) - (when (not complete) - (setq residual (car (last lines))) - (setq lines (butlast lines))) - (list lines residual)))) - -(defun flymake-reformat-err-line-patterns-from-compile-el (original-list) - "Grab error line patterns from ORIGINAL-LIST in compile.el format. -Convert it to flymake internal format." - (let* ((converted-list '())) - (dolist (item original-list) - (setq item (cdr item)) - (let ((regexp (nth 0 item)) - (file (nth 1 item)) - (line (nth 2 item)) - (col (nth 3 item))) - (if (consp file) (setq file (car file))) - (if (consp line) (setq line (car line))) - (if (consp col) (setq col (car col))) - - (when (not (functionp line)) - (setq converted-list (cons (list regexp file line col) converted-list))))) - converted-list)) - -(require 'compile) - -(defvar flymake-err-line-patterns ; regexp file-idx line-idx col-idx (optional) text-idx(optional), match-end to end of string is error text - (append - '( - ;; MS Visual C++ 6.0 - ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) : \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)" - 1 3 nil 4) - ;; jikes - ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:[0-9]+: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)" - 1 3 nil 4) - ;; MS midl - ("midl[ ]*:[ ]*\\(command line error .*\\)" - nil nil nil 1) - ;; MS C# - ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+): \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)" - 1 3 nil 4) - ;; perl - ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1) - ;; PHP - ("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 2 3 nil 1) - ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1) - ;; ant/javac. Note this also matches gcc warnings! - (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\):\\([0-9]+\\)\\(?::[0-9]+\\)?:[ \t\n]*\\(.+\\)" - 2 4 nil 5)) - ;; compilation-error-regexp-alist) - (flymake-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist)) - "Patterns for matching error/warning lines. Each pattern has the form -\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX). -Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns -from compile.el") - -(define-obsolete-variable-alias 'flymake-warning-re 'flymake-warning-predicate "24.4") -(defvar flymake-warning-predicate "^[wW]arning" - "Predicate matching against error text to detect a warning. -Takes a single argument, the error's text and should return non-nil -if it's a warning. -Instead of a function, it can also be a regular expression.") - -(defun flymake-parse-line (line) - "Parse LINE to see if it is an error or warning. -Return its components if so, nil otherwise." - (let ((raw-file-name nil) - (line-no 0) - (err-type "e") - (err-text nil) - (patterns flymake-err-line-patterns) - (matched nil)) - (while (and patterns (not matched)) - (when (string-match (car (car patterns)) line) - (let* ((file-idx (nth 1 (car patterns))) - (line-idx (nth 2 (car patterns)))) - - (setq raw-file-name (if file-idx (match-string file-idx line) nil)) - (setq line-no (if line-idx (string-to-number - (match-string line-idx line)) 0)) - (setq err-text (if (> (length (car patterns)) 4) - (match-string (nth 4 (car patterns)) line) - (flymake-patch-err-text - (substring line (match-end 0))))) - (if (null err-text) - (setq err-text "<no error text>") - (when (cond ((stringp flymake-warning-predicate) - (string-match flymake-warning-predicate err-text)) - ((functionp flymake-warning-predicate) - (funcall flymake-warning-predicate err-text))) - (setq err-type "w"))) - (flymake-log - 3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s" - file-idx line-idx raw-file-name line-no err-text) - (setq matched t))) - (setq patterns (cdr patterns))) - (if matched - (flymake-ler-make-ler raw-file-name line-no err-type err-text) - ()))) - -(defun flymake-find-err-info (err-info-list line-no) - "Find (line-err-info-list pos) for specified LINE-NO." - (if err-info-list - (let* ((line-err-info-list nil) - (pos 0) - (count (length err-info-list))) - - (while (and (< pos count) (< (car (nth pos err-info-list)) line-no)) - (setq pos (1+ pos))) - (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no)) - (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list)))) - (list line-err-info-list pos)) - '(nil 0))) - -(defun flymake-line-err-info-is-less-or-equal (line-one line-two) - (or (string< (flymake-ler-type line-one) (flymake-ler-type line-two)) - (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two)) - (not (flymake-ler-file line-one)) (flymake-ler-file line-two)) - (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two)) - (or (and (flymake-ler-file line-one) (flymake-ler-file line-two)) - (and (not (flymake-ler-file line-one)) (not (flymake-ler-file line-two))))))) - -(defun flymake-add-line-err-info (line-err-info-list line-err-info) - "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO. -For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'. -The new element is inserted in the proper position, according to -the predicate `flymake-line-err-info-is-less-or-equal'. -The updated value of LINE-ERR-INFO-LIST is returned." - (if (not line-err-info-list) - (list line-err-info) - (let* ((count (length line-err-info-list)) - (idx 0)) - (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info)) - (setq idx (1+ idx))) - (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list))) - (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info)))) - line-err-info-list))) - -(defun flymake-add-err-info (err-info-list line-err-info) - "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order. -Returns the updated value of ERR-INFO-LIST. -For the format of ERR-INFO-LIST, see `flymake-err-info'. -For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'." - (let* ((line-no (if (flymake-ler-file line-err-info) 1 (flymake-ler-line line-err-info))) - (info-and-pos (flymake-find-err-info err-info-list line-no)) - (exists (car info-and-pos)) - (pos (nth 1 info-and-pos)) - (line-err-info-list nil) - (err-info nil)) - - (if exists - (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list))))) - (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info)) - - (setq err-info (flymake-er-make-er line-no line-err-info-list)) - (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info))) - ((equal 0 pos) (setq err-info-list (cons err-info err-info-list))) - (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info)))) - err-info-list)) - -(defun flymake-get-project-include-dirs-imp (basedir) - "Include dirs for the project current file belongs to." - (if (flymake-get-project-include-dirs-from-cache basedir) - (progn - (flymake-get-project-include-dirs-from-cache basedir)) - ;;else - (let* ((command-line (concat "make -C " - (shell-quote-argument basedir) - " DUMPVARS=INCLUDE_DIRS dumpvars")) - (output (shell-command-to-string command-line)) - (lines (split-string output "\n" t)) - (count (length lines)) - (idx 0) - (inc-dirs nil)) - (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx lines)))) - (setq idx (1+ idx))) - (when (< idx count) - (let* ((inc-lines (split-string (nth idx lines) " *-I" t)) - (inc-count (length inc-lines))) - (while (> inc-count 0) - (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines))) - (push (replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs)) - (setq inc-count (1- inc-count))))) - (flymake-add-project-include-dirs-to-cache basedir inc-dirs) - inc-dirs))) - -(defvar flymake-get-project-include-dirs-function #'flymake-get-project-include-dirs-imp - "Function used to get project include dirs, one parameter: basedir name.") - -(defun flymake-get-project-include-dirs (basedir) - (funcall flymake-get-project-include-dirs-function basedir)) - -(defun flymake-get-system-include-dirs () - "System include dirs - from the `INCLUDE' env setting." - (let* ((includes (getenv "INCLUDE"))) - (if includes (split-string includes path-separator t) nil))) - -(defvar flymake-project-include-dirs-cache (make-hash-table :test #'equal)) - -(defun flymake-get-project-include-dirs-from-cache (base-dir) - (gethash base-dir flymake-project-include-dirs-cache)) - -(defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs) - (puthash base-dir include-dirs flymake-project-include-dirs-cache)) - -(defun flymake-clear-project-include-dirs-cache () - (clrhash flymake-project-include-dirs-cache)) - -(defun flymake-get-include-dirs (base-dir) - "Get dirs to use when resolving local file names." - (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs)))) - include-dirs)) - -;; (defun flymake-restore-formatting () -;; "Remove any formatting made by flymake." -;; ) - -;; (defun flymake-get-program-dir (buffer) -;; "Get dir to start program in." -;; (unless (bufferp buffer) -;; (error "Invalid buffer")) -;; (with-current-buffer buffer -;; default-directory)) - -(defun flymake-safe-delete-file (file-name) - (when (and file-name (file-exists-p file-name)) - (delete-file file-name) - (flymake-log 1 "deleted file %s" file-name))) - -(defun flymake-safe-delete-directory (dir-name) - (condition-case nil - (progn - (delete-directory dir-name) - (flymake-log 1 "deleted dir %s" dir-name)) - (error - (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name)))) - -(defun flymake-start-syntax-check () - "Start syntax checking for current buffer." - (interactive) - (flymake-log 3 "flymake is running: %s" flymake-is-running) - (when (and (not flymake-is-running) - (flymake-can-syntax-check-file buffer-file-name)) - (when (or (not flymake-compilation-prevents-syntax-check) - (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP") - (flymake-clear-buildfile-cache) - (flymake-clear-project-include-dirs-cache) - - (setq flymake-check-was-interrupted nil) - - (let* ((source-file-name buffer-file-name) - (init-f (flymake-get-init-function source-file-name)) - (cleanup-f (flymake-get-cleanup-function source-file-name)) - (cmd-and-args (funcall init-f)) - (cmd (nth 0 cmd-and-args)) - (args (nth 1 cmd-and-args)) - (dir (nth 2 cmd-and-args))) - (if (not cmd-and-args) - (progn - (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name) - (funcall cleanup-f)) - (progn - (setq flymake-last-change-time nil) - (flymake-start-syntax-check-process cmd args dir))))))) - -(defun flymake-start-syntax-check-process (cmd args dir) - "Start syntax check process." - (condition-case err - (let* ((process - (let ((default-directory (or dir default-directory))) - (when dir - (flymake-log 3 "starting process on dir %s" dir)) - (apply 'start-file-process - "flymake-proc" (current-buffer) cmd args)))) - (set-process-sentinel process 'flymake-process-sentinel) - (set-process-filter process 'flymake-process-filter) - (set-process-query-on-exit-flag process nil) - (push process flymake-processes) - - (setq flymake-is-running t) - (setq flymake-last-change-time nil) - (setq flymake-check-start-time (float-time)) - - (flymake-report-status nil "*") - (flymake-log 2 "started process %d, command=%s, dir=%s" - (process-id process) (process-command process) - default-directory) - process) - (error - (let* ((err-str - (format-message - "Failed to launch syntax check process `%s' with args %s: %s" - cmd args (error-message-string err))) - (source-file-name buffer-file-name) - (cleanup-f (flymake-get-cleanup-function source-file-name))) - (flymake-log 0 err-str) - (funcall cleanup-f) - (flymake-report-fatal-status "PROCERR" err-str))))) - -(defun flymake-kill-process (proc) - "Kill process PROC." - (kill-process proc) - (let* ((buf (process-buffer proc))) - (when (buffer-live-p buf) - (with-current-buffer buf - (setq flymake-check-was-interrupted t)))) - (flymake-log 1 "killed process %d" (process-id proc))) - -(defun flymake-stop-all-syntax-checks () - "Kill all syntax check processes." - (interactive) - (while flymake-processes - (flymake-kill-process (pop flymake-processes)))) - -(defun flymake-compilation-is-running () - (and (boundp 'compilation-in-progress) - compilation-in-progress)) - -(defun flymake-compile () - "Kill all flymake syntax checks, start compilation." - (interactive) - (flymake-stop-all-syntax-checks) - (call-interactively 'compile)) - -(defun flymake-on-timer-event (buffer) - "Start a syntax check for buffer BUFFER if necessary." - (when (buffer-live-p buffer) - (with-current-buffer buffer - (when (and (not flymake-is-running) - flymake-last-change-time - (> (- (float-time) flymake-last-change-time) - flymake-no-changes-timeout)) - - (setq flymake-last-change-time nil) - (flymake-log 3 "starting syntax check as more than 1 second passed since last change") - (flymake-start-syntax-check))))) - -(define-obsolete-function-alias 'flymake-display-err-menu-for-current-line - 'flymake-popup-current-error-menu "24.4") - -(defun flymake-popup-current-error-menu (&optional event) - "Pop up a menu with errors/warnings for current line." - (interactive (list last-nonmenu-event)) - (let* ((line-no (line-number-at-pos)) - (errors (or (car (flymake-find-err-info flymake-err-info line-no)) - (user-error "No errors for current line"))) - (menu (mapcar (lambda (x) - (if (flymake-ler-file x) - (cons (format "%s - %s(%d)" - (flymake-ler-text x) - (flymake-ler-file x) - (flymake-ler-line x)) - x) - (list (flymake-ler-text x)))) - errors)) - (event (if (mouse-event-p event) - event - (list 'mouse-1 (posn-at-point)))) - (title (format "Line %d: %d error(s), %d warning(s)" - line-no - (flymake-get-line-err-count errors "e") - (flymake-get-line-err-count errors "w"))) - (choice (x-popup-menu event (list title (cons "" menu))))) - (flymake-log 3 "choice=%s" choice) - (when choice - (flymake-goto-file-and-line (flymake-ler-full-file choice) - (flymake-ler-line choice))))) - -(defun flymake-goto-file-and-line (file line) - "Try to get buffer for FILE and goto line LINE in it." - (if (not (file-exists-p file)) - (flymake-log 1 "File %s does not exist" file) - (find-file file) - (goto-char (point-min)) - (forward-line (1- line)))) - -;; flymake minor mode declarations -(defvar-local flymake-mode-line nil) -(defvar-local flymake-mode-line-e-w nil) -(defvar-local flymake-mode-line-status nil) - -(defun flymake-report-status (e-w &optional status) - "Show status in mode line." - (when e-w - (setq flymake-mode-line-e-w e-w)) - (when status - (setq flymake-mode-line-status status)) - (let* ((mode-line " Flymake")) - (when (> (length flymake-mode-line-e-w) 0) - (setq mode-line (concat mode-line ":" flymake-mode-line-e-w))) - (setq mode-line (concat mode-line flymake-mode-line-status)) - (setq flymake-mode-line mode-line) - (force-mode-line-update))) - -;; Nothing in flymake uses this at all any more, so this is just for -;; third-party compatibility. -(define-obsolete-function-alias 'flymake-display-warning 'message-box "26.1") - -(defun flymake-report-fatal-status (status warning) - "Display a warning and switch flymake mode off." - ;; This first message was always shown by default, and flymake-log - ;; does nothing by default, hence the use of message. - ;; Another option is display-warning. - (if (< flymake-log-level 0) - (message "Flymake: %s. Flymake will be switched OFF" warning)) - (flymake-mode 0) - (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s" - (buffer-name) status warning)) - -;;;###autoload -(define-minor-mode flymake-mode nil - :group 'flymake :lighter flymake-mode-line - (cond - - ;; Turning the mode ON. - (flymake-mode - (cond - ((not buffer-file-name) - (message "Flymake unable to run without a buffer file name")) - ((not (flymake-can-syntax-check-file buffer-file-name)) - (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name))) - (t - (add-hook 'after-change-functions 'flymake-after-change-function nil t) - (add-hook 'after-save-hook 'flymake-after-save-hook nil t) - (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t) - ;;+(add-hook 'find-file-hook 'flymake-find-file-hook) - - (flymake-report-status "" "") - - (setq flymake-timer - (run-at-time nil 1 'flymake-on-timer-event (current-buffer))) - - (when (and flymake-start-syntax-check-on-find-file - ;; Since we write temp files in current dir, there's no point - ;; trying if the directory is read-only (bug#8954). - (file-writable-p (file-name-directory buffer-file-name))) - (with-demoted-errors - (flymake-start-syntax-check)))))) - - ;; Turning the mode OFF. - (t - (remove-hook 'after-change-functions 'flymake-after-change-function t) - (remove-hook 'after-save-hook 'flymake-after-save-hook t) - (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t) - ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t) - - (flymake-delete-own-overlays) - - (when flymake-timer - (cancel-timer flymake-timer) - (setq flymake-timer nil)) - - (setq flymake-is-running nil)))) - -;;;###autoload -(defun flymake-mode-on () - "Turn flymake mode on." - (flymake-mode 1) - (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name))) - -;;;###autoload -(defun flymake-mode-off () - "Turn flymake mode off." - (flymake-mode 0) - (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name))) - -(defun flymake-after-change-function (start stop _len) - "Start syntax check for current buffer if it isn't already running." - ;;+(flymake-log 0 "setting change time to %s" (float-time)) - (let((new-text (buffer-substring start stop))) - (when (and flymake-start-syntax-check-on-newline (equal new-text "\n")) - (flymake-log 3 "starting syntax check as new-line has been seen") - (flymake-start-syntax-check)) - (setq flymake-last-change-time (float-time)))) - -(defun flymake-after-save-hook () - (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved? - (progn - (flymake-log 3 "starting syntax check as buffer was saved") - (flymake-start-syntax-check)))) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???) - -(defun flymake-kill-buffer-hook () - (when flymake-timer - (cancel-timer flymake-timer) - (setq flymake-timer nil))) - -;;;###autoload -(defun flymake-find-file-hook () - ;;+(when flymake-start-syntax-check-on-find-file - ;;+ (flymake-log 3 "starting syntax check on file open") - ;;+ (flymake-start-syntax-check) - ;;+) - (when (and (not (local-variable-p 'flymake-mode (current-buffer))) - (flymake-can-syntax-check-file buffer-file-name)) - (flymake-mode) - (flymake-log 3 "automatically turned ON flymake mode"))) - -(defun flymake-get-first-err-line-no (err-info-list) - "Return first line with error." - (when err-info-list - (flymake-er-get-line (car err-info-list)))) - -(defun flymake-get-last-err-line-no (err-info-list) - "Return last line with error." - (when err-info-list - (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list)))) - -(defun flymake-get-next-err-line-no (err-info-list line-no) - "Return next line with error." - (when err-info-list - (let* ((count (length err-info-list)) - (idx 0)) - (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list)))) - (setq idx (1+ idx))) - (if (< idx count) - (flymake-er-get-line (nth idx err-info-list)))))) - -(defun flymake-get-prev-err-line-no (err-info-list line-no) - "Return previous line with error." - (when err-info-list - (let* ((count (length err-info-list))) - (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list)))) - (setq count (1- count))) - (if (> count 0) - (flymake-er-get-line (nth (1- count) err-info-list)))))) - -(defun flymake-skip-whitespace () - "Move forward until non-whitespace is reached." - (while (looking-at "[ \t]") - (forward-char))) - -(defun flymake-goto-line (line-no) - "Go to line LINE-NO, then skip whitespace." - (goto-char (point-min)) - (forward-line (1- line-no)) - (flymake-skip-whitespace)) - -(defun flymake-goto-next-error () - "Go to next error in err ring." - (interactive) - (let ((line-no (flymake-get-next-err-line-no flymake-err-info (line-number-at-pos)))) - (when (not line-no) - (setq line-no (flymake-get-first-err-line-no flymake-err-info)) - (flymake-log 1 "passed end of file")) - (if line-no - (flymake-goto-line line-no) - (flymake-log 1 "no errors in current buffer")))) - -(defun flymake-goto-prev-error () - "Go to previous error in err ring." - (interactive) - (let ((line-no (flymake-get-prev-err-line-no flymake-err-info (line-number-at-pos)))) - (when (not line-no) - (setq line-no (flymake-get-last-err-line-no flymake-err-info)) - (flymake-log 1 "passed beginning of file")) - (if line-no - (flymake-goto-line line-no) - (flymake-log 1 "no errors in current buffer")))) - -(defun flymake-patch-err-text (string) - (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string) - (match-string 1 string) - string)) - -;;;; general init-cleanup and helper routines -(defun flymake-create-temp-inplace (file-name prefix) - (unless (stringp file-name) - (error "Invalid file-name")) - (or prefix - (setq prefix "flymake")) - (let* ((ext (file-name-extension file-name)) - (temp-name (file-truename - (concat (file-name-sans-extension file-name) - "_" prefix - (and ext (concat "." ext)))))) - (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name) - temp-name)) - -(defun flymake-create-temp-with-folder-structure (file-name _prefix) - (unless (stringp file-name) - (error "Invalid file-name")) - - (let* ((dir (file-name-directory file-name)) - ;; Not sure what this slash-pos is all about, but I guess it's just - ;; trying to remove the leading / of absolute file names. - (slash-pos (string-match "/" dir)) - (temp-dir (expand-file-name (substring dir (1+ slash-pos)) - temporary-file-directory))) - - (file-truename (expand-file-name (file-name-nondirectory file-name) - temp-dir)))) - -(defun flymake-delete-temp-directory (dir-name) - "Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error." - (let* ((temp-dir temporary-file-directory) - (suffix (substring dir-name (1+ (length temp-dir))))) - - (while (> (length suffix) 0) - (setq suffix (directory-file-name suffix)) - ;;+(flymake-log 0 "suffix=%s" suffix) - (flymake-safe-delete-directory - (file-truename (expand-file-name suffix temp-dir))) - (setq suffix (file-name-directory suffix))))) - -(defvar-local flymake-temp-source-file-name nil) -(defvar-local flymake-master-file-name nil) -(defvar-local flymake-temp-master-file-name nil) -(defvar-local flymake-base-dir nil) - -(defun flymake-init-create-temp-buffer-copy (create-temp-f) - "Make a temporary copy of the current buffer, save its name in buffer data and return the name." - (let* ((source-file-name buffer-file-name) - (temp-source-file-name (funcall create-temp-f source-file-name "flymake"))) - - (flymake-save-buffer-in-file temp-source-file-name) - (setq flymake-temp-source-file-name temp-source-file-name) - temp-source-file-name)) - -(defun flymake-simple-cleanup () - "Do cleanup after `flymake-init-create-temp-buffer-copy'. -Delete temp file." - (flymake-safe-delete-file flymake-temp-source-file-name) - (setq flymake-last-change-time nil)) - -(defun flymake-get-real-file-name (file-name-from-err-msg) - "Translate file name from error message to \"real\" file name. -Return full-name. Names are real, not patched." - (let* ((real-name nil) - (source-file-name buffer-file-name) - (master-file-name flymake-master-file-name) - (temp-source-file-name flymake-temp-source-file-name) - (temp-master-file-name flymake-temp-master-file-name) - (base-dirs - (list flymake-base-dir - (file-name-directory source-file-name) - (if master-file-name (file-name-directory master-file-name)))) - (files (list (list source-file-name source-file-name) - (list temp-source-file-name source-file-name) - (list master-file-name master-file-name) - (list temp-master-file-name master-file-name)))) - - (when (equal 0 (length file-name-from-err-msg)) - (setq file-name-from-err-msg source-file-name)) - - (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files)) - ;; if real-name is nil, than file name from err msg is none of the files we've patched - (if (not real-name) - (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs))) - (if (not real-name) - (setq real-name file-name-from-err-msg)) - (setq real-name (flymake-fix-file-name real-name)) - (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name) - real-name)) - -(defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs files) - (let* ((base-dirs-count (length base-dirs)) - (file-count (length files)) - (real-name nil)) - - (while (and (not real-name) (> base-dirs-count 0)) - (setq file-count (length files)) - (while (and (not real-name) (> file-count 0)) - (let* ((this-dir (nth (1- base-dirs-count) base-dirs)) - (this-file (nth 0 (nth (1- file-count) files))) - (this-real-name (nth 1 (nth (1- file-count) files)))) - ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" this-dir this-file this-real-name file-name-from-err-msg) - (when (and this-dir this-file (flymake-same-files - (expand-file-name file-name-from-err-msg this-dir) - this-file)) - (setq real-name this-real-name))) - (setq file-count (1- file-count))) - (setq base-dirs-count (1- base-dirs-count))) - real-name)) - -(defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs) - (let* ((real-name nil)) - (if (file-name-absolute-p file-name-from-err-msg) - (setq real-name file-name-from-err-msg) - (let* ((base-dirs-count (length base-dirs))) - (while (and (not real-name) (> base-dirs-count 0)) - (let* ((full-name (expand-file-name file-name-from-err-msg - (nth (1- base-dirs-count) base-dirs)))) - (if (file-exists-p full-name) - (setq real-name full-name)) - (setq base-dirs-count (1- base-dirs-count)))))) - real-name)) - -(defun flymake-init-find-buildfile-dir (source-file-name buildfile-name) - "Find buildfile, store its dir in buffer data and return its dir, if found." - (let* ((buildfile-dir - (flymake-find-buildfile buildfile-name - (file-name-directory source-file-name)))) - (if buildfile-dir - (setq flymake-base-dir buildfile-dir) - (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name) - (flymake-report-fatal-status - "NOMK" (format "No buildfile (%s) found for %s" - buildfile-name source-file-name))))) - -(defun flymake-init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f create-temp-f master-file-masks include-regexp) - "Find master file (or buffer), create its copy along with a copy of the source file." - (let* ((source-file-name buffer-file-name) - (temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)) - (master-and-temp-master (flymake-create-master-file - source-file-name temp-source-file-name - get-incl-dirs-f create-temp-f - master-file-masks include-regexp))) - - (if (not master-and-temp-master) - (progn - (flymake-log 1 "cannot find master file for %s" source-file-name) - (flymake-report-status "!" "") ; NOMASTER - nil) - (setq flymake-master-file-name (nth 0 master-and-temp-master)) - (setq flymake-temp-master-file-name (nth 1 master-and-temp-master))))) - -(defun flymake-master-cleanup () - (flymake-simple-cleanup) - (flymake-safe-delete-file flymake-temp-master-file-name)) - -;;;; make-specific init-cleanup routines -(defun flymake-get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f) - "Create a command line for syntax check using GET-CMD-LINE-F." - (funcall get-cmd-line-f - (if use-relative-source - (file-relative-name source-file-name base-dir) - source-file-name) - (if use-relative-base-dir - (file-relative-name base-dir - (file-name-directory source-file-name)) - base-dir))) - -(defun flymake-get-make-cmdline (source base-dir) - (list "make" - (list "-s" - "-C" - base-dir - (concat "CHK_SOURCES=" source) - "SYNTAX_CHECK_MODE=1" - "check-syntax"))) - -(defun flymake-get-ant-cmdline (source base-dir) - (list "ant" - (list "-buildfile" - (concat base-dir "/" "build.xml") - (concat "-DCHK_SOURCES=" source) - "check-syntax"))) - -(defun flymake-simple-make-init-impl (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f) - "Create syntax check command line for a directly checked source file. -Use CREATE-TEMP-F for creating temp copy." - (let* ((args nil) - (source-file-name buffer-file-name) - (buildfile-dir (flymake-init-find-buildfile-dir source-file-name build-file-name))) - (if buildfile-dir - (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f))) - (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir - use-relative-base-dir use-relative-source - get-cmdline-f)))) - args)) - -(defun flymake-simple-make-init () - (flymake-simple-make-init-impl 'flymake-create-temp-inplace t t "Makefile" 'flymake-get-make-cmdline)) - -(defun flymake-master-make-init (get-incl-dirs-f master-file-masks include-regexp) - "Create make command line for a source file checked via master file compilation." - (let* ((make-args nil) - (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy - get-incl-dirs-f 'flymake-create-temp-inplace - master-file-masks include-regexp))) - (when temp-master-file-name - (let* ((buildfile-dir (flymake-init-find-buildfile-dir temp-master-file-name "Makefile"))) - (if buildfile-dir - (setq make-args (flymake-get-syntax-check-program-args - temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline))))) - make-args)) - -(defun flymake-find-make-buildfile (source-dir) - (flymake-find-buildfile "Makefile" source-dir)) - -;;;; .h/make specific -(defun flymake-master-make-header-init () - (flymake-master-make-init - 'flymake-get-include-dirs - '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'") - "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\"")) - -;;;; .java/make specific -(defun flymake-simple-make-java-init () - (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline)) - -(defun flymake-simple-ant-java-init () - (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline)) - -(defun flymake-simple-java-cleanup () - "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs." - (flymake-safe-delete-file flymake-temp-source-file-name) - (when flymake-temp-source-file-name - (flymake-delete-temp-directory - (file-name-directory flymake-temp-source-file-name)))) - -;;;; perl-specific init-cleanup routines -(defun flymake-perl-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-inplace)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name)))) - (list "perl" (list "-wc " local-file)))) - -;;;; php-specific init-cleanup routines -(defun flymake-php-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-inplace)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name)))) - (list "php" (list "-f" local-file "-l")))) - -;;;; tex-specific init-cleanup routines -(defun flymake-get-tex-args (file-name) - ;;(list "latex" (list "-c-style-errors" file-name)) - (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name))) - -(defun flymake-simple-tex-init () - (flymake-get-tex-args (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace))) - -;; Perhaps there should be a buffer-local variable flymake-master-file -;; that people can set to override this stuff. Could inherit from -;; the similar AUCTeX variable. -(defun flymake-master-tex-init () - (let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy - 'flymake-get-include-dirs-dot 'flymake-create-temp-inplace - '("\\.tex\\'") - "[ \t]*\\in\\(?:put\\|clude\\)[ \t]*{\\(.*%s\\)}"))) - (when temp-master-file-name - (flymake-get-tex-args temp-master-file-name)))) - -(defun flymake-get-include-dirs-dot (_base-dir) - '(".")) - -;;;; xml-specific init-cleanup routines -(defun flymake-xml-init () - (list flymake-xml-program - (list "val" (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-inplace)))) +(require 'flymake-ui) +(require 'flymake-proc) (provide 'flymake) ;;; flymake.el ends here diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el index 9231e118907..92a42b1cb94 100644 --- a/lisp/progmodes/idlwave.el +++ b/lisp/progmodes/idlwave.el @@ -5240,7 +5240,7 @@ Can run from `after-save-hook'." class (cond ((not (boundp 'idlwave-scanning-lib)) (list 'buffer (buffer-file-name))) -; ((string= (downcase (file-name-base)) +; ((string= (downcase (file-name-base (buffer-file-name)) ; (downcase name)) ; (list 'lib)) ; (t (cons 'lib (file-name-nondirectory (buffer-file-name)))) diff --git a/lisp/register.el b/lisp/register.el index 913380763c6..23eefd08b88 100644 --- a/lisp/register.el +++ b/lisp/register.el @@ -182,8 +182,11 @@ Use \\[jump-to-register] to go to that location or restore that configuration. Argument is a character, naming the register. Interactively, reads the register using `register-read-with-preview'." - (interactive (list (register-read-with-preview "Point to register: ") - current-prefix-arg)) + (interactive (list (register-read-with-preview + (if current-prefix-arg + "Frame configuration to register: " + "Point to register: ")) + current-prefix-arg)) ;; Turn the marker into a file-ref if the buffer is killed. (add-hook 'kill-buffer-hook 'register-swap-out nil t) (set-register register diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el index 4f79703833d..6a17d382b0a 100644 --- a/lisp/term/xterm.el +++ b/lisp/term/xterm.el @@ -68,6 +68,11 @@ string bytes that can be copied is 3/4 of this value." :version "25.1" :type 'integer) +(defcustom xterm-set-window-title t + "Whether Emacs should set window titles to an Emacs frame in an XTerm." + :version "27.1" + :type 'boolean) + (defconst xterm-paste-ending-sequence "\e[201~" "Characters send by the terminal to end a bracketed paste.") @@ -802,6 +807,8 @@ We run the first FUNCTION whose STRING matches the input events." (when (memq 'setSelection xterm-extra-capabilities) (xterm--init-activate-set-selection))) + (when xterm-set-window-title + (xterm--init-frame-title)) ;; Unconditionally enable bracketed paste mode: terminals that don't ;; support it just ignore the sequence. (xterm--init-bracketed-paste-mode) @@ -828,6 +835,34 @@ We run the first FUNCTION whose STRING matches the input events." "Terminal initialization for `gui-set-selection'." (set-terminal-parameter nil 'xterm--set-selection t)) +(defun xterm--init-frame-title () + "Terminal initialization for XTerm frame titles." + (xterm-set-window-title) + (add-hook 'after-make-frame-functions 'xterm-set-window-title-flag) + (add-hook 'window-configuration-change-hook 'xterm-unset-window-title-flag) + (add-hook 'post-command-hook 'xterm-set-window-title) + (add-hook 'minibuffer-exit-hook 'xterm-set-window-title)) + +(defvar xterm-window-title-flag nil + "Whether a new frame has been created, calling for a title update.") + +(defun xterm-set-window-title-flag (_frame) + "Set `xterm-window-title-flag'. +See `xterm--init-frame-title'" + (setq xterm-window-title-flag t)) + +(defun xterm-unset-window-title-flag () + (when xterm-window-title-flag + (setq xterm-window-title-flag nil) + (xterm-set-window-title))) + +(defun xterm-set-window-title (&optional terminal) + "Set the window title of the Xterm TERMINAL. +The title is constructed from `frame-title-format'." + (send-string-to-terminal + (format "\e]2;%s\a" (format-mode-line frame-title-format)) + terminal)) + (defun xterm--selection-char (type) (pcase type ('PRIMARY "p") diff --git a/lisp/textmodes/page-ext.el b/lisp/textmodes/page-ext.el index 94b68decfb7..bf1e33bf0f6 100644 --- a/lisp/textmodes/page-ext.el +++ b/lisp/textmodes/page-ext.el @@ -1,4 +1,4 @@ -;;; page-ext.el --- extended page handling commands +;;; page-ext.el --- extended page handling commands -*- lexical-binding:t -*- ;; Copyright (C) 1990-1991, 1993-1994, 2001-2017 Free Software ;; Foundation, Inc. @@ -243,18 +243,15 @@ (defcustom pages-directory-buffer-narrowing-p t "If non-nil, `pages-directory-goto' narrows pages buffer to entry." - :type 'boolean - :group 'pages) + :type 'boolean) (defcustom pages-directory-for-adding-page-narrowing-p t "If non-nil, `add-new-page' narrows page buffer to new entry." - :type 'boolean - :group 'pages) + :type 'boolean) (defcustom pages-directory-for-adding-new-page-before-current-page-p t "If non-nil, `add-new-page' inserts new page before current page." - :type 'boolean - :group 'pages) + :type 'boolean) ;;; Addresses related variables @@ -262,23 +259,19 @@ (defcustom pages-addresses-file-name "~/addresses" "Standard name for file of addresses. Entries separated by page-delimiter. Used by `pages-directory-for-addresses' function." - :type 'file - :group 'pages) + :type 'file) (defcustom pages-directory-for-addresses-goto-narrowing-p t "If non-nil, `pages-directory-goto' narrows addresses buffer to entry." - :type 'boolean - :group 'pages) + :type 'boolean) (defcustom pages-directory-for-addresses-buffer-keep-windows-p t "If nil, `pages-directory-for-addresses' deletes other windows." - :type 'boolean - :group 'pages) + :type 'boolean) (defcustom pages-directory-for-adding-addresses-narrowing-p t "If non-nil, `add-new-page' narrows addresses buffer to new entry." - :type 'boolean - :group 'pages) + :type 'boolean) ;;; Key bindings for page handling functions @@ -415,9 +408,9 @@ Point is left in the body of page." Called from a program, there are three arguments: REVERSE (non-nil means reverse order), BEG and END (region to sort)." -;;; This sort function handles ends of pages differently than -;;; `sort-pages' and works better with lists of addresses and similar -;;; files. + ;; This sort function handles ends of pages differently than + ;; `sort-pages' and works better with lists of addresses and similar + ;; files. (interactive "P\nr") (save-restriction @@ -463,25 +456,27 @@ REVERSE (non-nil means reverse order), BEG and END (region to sort)." \(This regular expression may be used to select only those pages that contain matches to the regexp.)") -(defvar pages-buffer nil +(defvar-local pages-buffer nil "The buffer for which the pages-directory function creates the directory.") (defvar pages-directory-prefix "*Directory for:" "Prefix of name of temporary buffer for pages-directory.") -(defvar pages-pos-list nil +(defvar-local pages-pos-list nil "List containing the positions of the pages in the pages-buffer.") (defvar pages-target-buffer) +(define-obsolete-variable-alias 'pages-directory-map + 'pages-directory-mode-map "26.1") (defvar pages-directory-mode-map (let ((map (make-sparse-keymap))) (define-key map "\C-c\C-c" 'pages-directory-goto) + (define-key map "\C-m" 'pages-directory-goto) (define-key map "\C-c\C-p\C-a" 'add-new-page) - (define-key map [mouse-2] 'pages-directory-goto-with-mouse) + (define-key map [mouse-2] 'pages-directory-goto) map) "Keymap for the pages-directory-buffer.") -(defvaralias 'pages-directory-map 'pages-directory-mode-map) (defvar original-page-delimiter "^\f" "Default page delimiter.") @@ -512,6 +507,9 @@ resets the page-delimiter to the original value." ;;; Pages directory main definitions +(defvar pages-buffer-original-position) +(defvar pages-buffer-original-page) + (defun pages-directory (pages-list-all-headers-p count-lines-p &optional regexp) "Display a directory of the page headers in a temporary buffer. @@ -573,7 +571,6 @@ directory for only the accessible portion of the buffer." (let ((pages-target-buffer (current-buffer)) (pages-directory-buffer (concat pages-directory-prefix " " (buffer-name))) - (linenum 1) (pages-buffer-original-position (point)) (pages-buffer-original-page 0)) @@ -644,10 +641,6 @@ directory for only the accessible portion of the buffer." 1 pages-buffer-original-page)))) -(defvar pages-buffer-original-position) -(defvar pages-buffer-original-page) -(defvar pages-buffer-original-page) - (defun pages-copy-header-and-position (count-lines-p) "Copy page header and its position to the Pages Directory. Only arg non-nil, count lines in page and insert before header. @@ -701,16 +694,13 @@ Used by `pages-directory' function." Move point to one of the lines in this buffer, then use \\[pages-directory-goto] to go to the same line in the pages buffer." - (make-local-variable 'pages-buffer) - (make-local-variable 'pages-pos-list) (make-local-variable 'pages-directory-buffer-narrowing-p)) -(defun pages-directory-goto () +(defun pages-directory-goto (&optional event) "Go to the corresponding line in the pages buffer." - -;;; This function is mostly a copy of `occur-mode-goto-occurrence' - - (interactive) + ;; This function is mostly a copy of `occur-mode-goto-occurrence' + (interactive "@e") + (if event (mouse-set-point event)) (if (or (not pages-buffer) (not (buffer-name pages-buffer))) (progn @@ -724,18 +714,13 @@ to the same line in the pages buffer." (narrowing-p pages-directory-buffer-narrowing-p)) (pop-to-buffer pages-buffer) (widen) - (if end-of-directory-p - (goto-char (point-max)) - (goto-char (marker-position pos))) + (goto-char (if end-of-directory-p + (point-max) + (marker-position pos))) (if narrowing-p (narrow-to-page)))) -(defun pages-directory-goto-with-mouse (event) - "Go to the corresponding line under the mouse pointer in the pages buffer." - (interactive "e") - (with-current-buffer (window-buffer (posn-window (event-end event))) - (save-excursion - (goto-char (posn-point (event-end event))) - (pages-directory-goto)))) +(define-obsolete-function-alias 'pages-directory-goto-with-mouse + #'pages-directory-goto "26.1") ;;; The `pages-directory-for-addresses' function and ancillary code diff --git a/lisp/textmodes/reftex-ref.el b/lisp/textmodes/reftex-ref.el index c2c5ca3de06..f9f23201b43 100644 --- a/lisp/textmodes/reftex-ref.el +++ b/lisp/textmodes/reftex-ref.el @@ -314,7 +314,7 @@ also applies `reftex-translate-to-ascii-function' to the string." (save-match-data (cond ((equal letter "f") - (file-name-base)) + (file-name-base (buffer-file-name))) ((equal letter "F") (let ((masterdir (file-name-directory (reftex-TeX-master-file))) (file (file-name-sans-extension (buffer-file-name)))) diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el index 485cc97555f..e3a4d4d7c1e 100644 --- a/lisp/thingatpt.el +++ b/lisp/thingatpt.el @@ -42,6 +42,9 @@ ;; beginning-op Function to call to skip to the beginning of a "thing". ;; end-op Function to call to skip to the end of a "thing". ;; +;; For simple things, defined as sequences of specific kinds of characters, +;; use macro define-thing-chars. +;; ;; Reliance on existing operators means that many `things' can be accessed ;; without further code: eg. ;; (thing-at-point 'line) @@ -237,21 +240,28 @@ The bounds of THING are determined by `bounds-of-thing-at-point'." (put 'defun 'end-op 'end-of-defun) (put 'defun 'forward-op 'end-of-defun) +;; Things defined by sets of characters + +(defmacro define-thing-chars (thing chars) + "Define THING as a sequence of CHARS. +E.g.: +\(define-thing-chars twitter-screen-name \"[:alnum:]_\")" + `(progn + (put ',thing 'end-op + (lambda () + (re-search-forward (concat "\\=[" ,chars "]*") nil t))) + (put ',thing 'beginning-op + (lambda () + (if (re-search-backward (concat "[^" ,chars "]") nil t) + (forward-char) + (goto-char (point-min))))))) + ;; Filenames (defvar thing-at-point-file-name-chars "-~/[:alnum:]_.${}#%,:" "Characters allowable in filenames.") -(put 'filename 'end-op - (lambda () - (re-search-forward (concat "\\=[" thing-at-point-file-name-chars "]*") - nil t))) -(put 'filename 'beginning-op - (lambda () - (if (re-search-backward (concat "[^" thing-at-point-file-name-chars "]") - nil t) - (forward-char) - (goto-char (point-min))))) +(define-thing-chars filename thing-at-point-file-name-chars) ;; URIs diff --git a/lisp/xdg.el b/lisp/xdg.el index 76106f42586..4250faaeb4b 100644 --- a/lisp/xdg.el +++ b/lisp/xdg.el @@ -34,6 +34,7 @@ ;;; Code: (eval-when-compile + (require 'cl-lib) (require 'subr-x)) @@ -212,6 +213,108 @@ Optional argument GROUP defaults to the string \"Desktop Entry\"." (when (null (string-match-p "[^[:blank:]]" (car res))) (pop res)) (nreverse res))) + +;; MIME apps specification +;; https://standards.freedesktop.org/mime-apps-spec/mime-apps-spec-1.0.1.html + +(defvar xdg-mime-table nil + "Table of MIME type to desktop file associations. +The table is an alist with keys being MIME major types (\"application\", +\"audio\", etc.), and values being hash tables. Each hash table has +MIME subtypes as keys and lists of desktop file absolute filenames.") + +(defun xdg-mime-apps-files () + "Return a list of files containing MIME/Desktop associations. +The list is in order of descending priority: user config, then +admin config, and finally system cached associations." + (let ((xdg-data-dirs (xdg-data-dirs)) + (desktop (getenv "XDG_CURRENT_DESKTOP")) + res) + (when desktop + (setq desktop (format "%s-mimeapps.list" desktop))) + (dolist (name (cons "mimeapps.list" desktop)) + (push (expand-file-name name (xdg-config-home)) res) + (push (expand-file-name (format "applications/%s" name) (xdg-data-home)) + res) + (dolist (dir (xdg-config-dirs)) + (push (expand-file-name name dir) res)) + (dolist (dir xdg-data-dirs) + (push (expand-file-name (format "applications/%s" name) dir) res))) + (dolist (dir xdg-data-dirs) + (push (expand-file-name "applications/mimeinfo.cache" dir) res)) + (nreverse res))) + +(defun xdg-mime-collect-associations (mime files) + "Return a list of desktop file names associated with MIME. +The associations are searched in the list of file names FILES, +which is expected to be ordered by priority as in +`xdg-mime-apps-files'." + (let ((regexp (concat (regexp-quote mime) "=\\([^[:cntrl:]]*\\)$")) + res sec defaults added removed cached) + (with-temp-buffer + (dolist (f (reverse files)) + (when (file-readable-p f) + (insert-file-contents-literally f nil nil nil t) + (goto-char (point-min)) + (let (end) + (while (not (or (eobp) end)) + (if (= (following-char) ?\[) + (progn (setq sec (char-after (1+ (point)))) + (forward-line)) + (if (not (looking-at regexp)) + (forward-line) + (dolist (str (xdg-desktop-strings (match-string 1))) + (cl-pushnew str + (cond ((eq sec ?D) defaults) + ((eq sec ?A) added) + ((eq sec ?R) removed) + ((eq sec ?M) cached)) + :test #'equal)) + (while (and (zerop (forward-line)) + (/= (following-char) ?\[))))))) + ;; Accumulate results into res + (dolist (f cached) + (when (not (member f removed)) (cl-pushnew f res :test #'equal))) + (dolist (f added) + (when (not (member f removed)) (push f res))) + (dolist (f removed) + (setq res (delete f res))) + (dolist (f defaults) + (push f res)) + (setq defaults nil added nil removed nil cached nil)))) + (delete-dups res))) + +(defun xdg-mime-apps (mime) + "Return list of desktop files associated with MIME, otherwise nil. +The list is in order of descending priority, and each element is +an absolute file name of a readable file. +Results are cached in `xdg-mime-table'." + (pcase-let ((`(,type ,subtype) (split-string mime "/")) + (xdg-data-dirs (xdg-data-dirs)) + (caches (xdg-mime-apps-files)) + (files ())) + (let ((mtim1 (get 'xdg-mime-table 'mtime)) + (mtim2 (cl-loop for f in caches when (file-readable-p f) + maximize (float-time (nth 5 (file-attributes f)))))) + ;; If one of the MIME/Desktop cache files has been modified: + (when (or (null mtim1) (time-less-p mtim1 mtim2)) + (setq xdg-mime-table nil))) + (when (null (assoc type xdg-mime-table)) + (push (cons type (make-hash-table :test #'equal)) xdg-mime-table)) + (if (let ((def (make-symbol "def")) + (table (cdr (assoc type xdg-mime-table)))) + (not (eq (setq files (gethash subtype table def)) def))) + files + (and files (setq files nil)) + (let ((dirs (mapcar (lambda (dir) (expand-file-name "applications" dir)) + (cons (xdg-data-home) xdg-data-dirs)))) + ;; Not being particular about desktop IDs + (dolist (f (nreverse (xdg-mime-collect-associations mime caches))) + (push (locate-file f dirs) files)) + (when files + (put 'xdg-mime-table 'mtime (current-time))) + (puthash subtype (delq nil files) (cdr (assoc type xdg-mime-table))))))) + (provide 'xdg) ;;; xdg.el ends here diff --git a/msdos/sed2v2.inp b/msdos/sed2v2.inp index be685710fd8..7769ba30495 100644 --- a/msdos/sed2v2.inp +++ b/msdos/sed2v2.inp @@ -66,7 +66,7 @@ /^#undef PACKAGE_TARNAME/s/^.*$/#define PACKAGE_TARNAME ""/ /^#undef PACKAGE_VERSION/s/^.*$/#define PACKAGE_VERSION VERSION/ /^#undef PENDING_OUTPUT_COUNT/s/^.*$/#define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base)/ -/^#undef VERSION/s/^.*$/#define VERSION "26.0.60"/ +/^#undef VERSION/s/^.*$/#define VERSION "27.0.50"/ /^#undef SYSTEM_TYPE/s/^.*$/#define SYSTEM_TYPE "ms-dos"/ /^#undef HAVE_DECL_GETENV/s/^.*$/#define HAVE_DECL_GETENV 1/ /^#undef SYS_SIGLIST_DECLARED/s/^.*$/#define SYS_SIGLIST_DECLARED 1/ diff --git a/nt/INSTALL.W64 b/nt/INSTALL.W64 index 841660bf0f9..4a93dc02c8b 100644 --- a/nt/INSTALL.W64 +++ b/nt/INSTALL.W64 @@ -112,11 +112,11 @@ C:\emacs\emacs-24.5: ** From the Git repository To download the Git repository, do something like the following -- this will -put the Emacs source into C:\emacs\emacs-25: +put the Emacs source into C:\emacs\emacs-26: mkdir /c/emacs cd /c/emacs - git clone git://git.sv.gnu.org/emacs.git emacs-25 + git clone git://git.sv.gnu.org/emacs.git emacs-26 (We recommend using the command shown on Savannah Emacs project page.) @@ -129,7 +129,7 @@ First we need to switch to the MinGW-w64 environment. Exit the MSYS2 BASH console and run mingw64_shell.bat in the C:\msys64 folder, then cd back to your Emacs source directory, e.g.: - cd /c/emacs/emacs-25 + cd /c/emacs/emacs-26 ** Run autogen @@ -146,7 +146,7 @@ that the example given here is just a simple one - for more information on the options available please see the INSTALL file in this directory. The '--prefix' option specifies a location for the resulting binary files, -which 'make install' will use - in this example we set it to C:\emacs\emacs-25. +which 'make install' will use - in this example we set it to C:\emacs\emacs-26. If a prefix is not specified the files will be put in the standard Unix directories located in your C:\msys64 directory, but this is not recommended. @@ -154,7 +154,7 @@ Note also that we need to disable Imagemagick because Emacs does not yet support it on Windows. PKG_CONFIG_PATH=/mingw64/lib/pkgconfig \ - ./configure --prefix=/c/emacs/emacs-25 --without-imagemagick + ./configure --prefix=/c/emacs/emacs-26 --without-imagemagick ** Run make diff --git a/nt/README.W32 b/nt/README.W32 index 0a15965f468..e996c8e672c 100644 --- a/nt/README.W32 +++ b/nt/README.W32 @@ -1,7 +1,7 @@ Copyright (C) 2001-2017 Free Software Foundation, Inc. See the end of the file for license conditions. - Emacs version 26.0.60 for MS-Windows + Emacs version 27.0.50 for MS-Windows This README file describes how to set up and run a precompiled distribution of the latest version of GNU Emacs for MS-Windows. You diff --git a/src/data.c b/src/data.c index e070be6c208..2e7f3e017be 100644 --- a/src/data.c +++ b/src/data.c @@ -3069,6 +3069,22 @@ usage: (logxor &rest INTS-OR-MARKERS) */) return arith_driver (Alogxor, nargs, args); } +DEFUN ("logcount", Flogcount, Slogcount, 1, 1, 0, + doc: /* Return population count of VALUE. +This is the number of one bits in the two's complement representation +of VALUE. If VALUE is negative, return the number of zero bits in the +representation. */) + (Lisp_Object value) +{ + CHECK_NUMBER (value); + EMACS_INT v = XINT (value) < 0 ? -1 - XINT (value) : XINT (value); + return make_number (EMACS_UINT_WIDTH <= UINT_WIDTH + ? count_one_bits (v) + : EMACS_UINT_WIDTH <= ULONG_WIDTH + ? count_one_bits_l (v) + : count_one_bits_ll (v)); +} + static Lisp_Object ash_lsh_impl (Lisp_Object value, Lisp_Object count, bool lsh) { @@ -3856,6 +3872,7 @@ syms_of_data (void) defsubr (&Slogand); defsubr (&Slogior); defsubr (&Slogxor); + defsubr (&Slogcount); defsubr (&Slsh); defsubr (&Sash); defsubr (&Sadd1); diff --git a/src/editfns.c b/src/editfns.c index e326604467c..4dcf7cbe6ef 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -1256,10 +1256,10 @@ If POS is out of range, the value is nil. */) if (NILP (pos)) { pos_byte = PT_BYTE; - XSETFASTINT (pos, PT); + if (pos_byte < BEGV_BYTE || pos_byte >= ZV_BYTE) + return Qnil; } - - if (MARKERP (pos)) + else if (MARKERP (pos)) { pos_byte = marker_byte_position (pos); if (pos_byte < BEGV_BYTE || pos_byte >= ZV_BYTE) diff --git a/src/gtkutil.c b/src/gtkutil.c index a07ee4b1b02..8d565c19c9c 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -1054,16 +1054,23 @@ static void xg_set_widget_bg (struct frame *f, GtkWidget *w, unsigned long pixel) { #ifdef HAVE_GTK3 - GdkRGBA bg; XColor xbg; xbg.pixel = pixel; if (XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &xbg)) { - bg.red = (double)xbg.red/65535.0; - bg.green = (double)xbg.green/65535.0; - bg.blue = (double)xbg.blue/65535.0; - bg.alpha = 1.0; - gtk_widget_override_background_color (w, GTK_STATE_FLAG_NORMAL, &bg); + const char format[] = "* { background-color: #%02x%02x%02x; }"; + /* The format is always longer than the resulting string. */ + char buffer[sizeof format]; + int n = snprintf(buffer, sizeof buffer, format, + xbg.red >> 8, xbg.green >> 8, xbg.blue >> 8); + eassert (n > 0); + eassert (n < sizeof buffer); + GtkCssProvider *provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, buffer, -1, NULL); + gtk_style_context_add_provider (gtk_widget_get_style_context(w), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_clear_object (&provider); } #else GdkColor bg; @@ -1227,9 +1234,11 @@ xg_create_frame_widgets (struct frame *f) X and GTK+ drawing to a pure GTK+ build. */ gtk_widget_set_double_buffered (wfixed, FALSE); +#if ! GTK_CHECK_VERSION (3, 22, 0) gtk_window_set_wmclass (GTK_WINDOW (wtop), SSDATA (Vx_resource_name), SSDATA (Vx_resource_class)); +#endif /* Add callback to do nothing on WM_DELETE_WINDOW. The default in GTK is to destroy the widget. We want Emacs to do that instead. */ @@ -4092,8 +4101,10 @@ xg_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, if (int_gtk_range_get_value (GTK_RANGE (wscroll)) != value) gtk_range_set_value (GTK_RANGE (wscroll), (gdouble)value); +#if ! GTK_CHECK_VERSION (3, 18, 0) else if (changed) gtk_adjustment_changed (adj); +#endif xg_ignore_gtk_scrollbar = 0; @@ -4130,7 +4141,9 @@ xg_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, gtk_adjustment_configure (adj, (gdouble) value, (gdouble) lower, (gdouble) upper, (gdouble) step_increment, (gdouble) page_increment, (gdouble) pagesize); +#if ! GTK_CHECK_VERSION (3, 18, 0) gtk_adjustment_changed (adj); +#endif unblock_input (); } } diff --git a/src/msdos.c b/src/msdos.c index 68daa10fdb9..a8aef9ac405 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -1791,7 +1791,7 @@ internal_terminal_init (void) } Vinitial_window_system = Qpc; - Vwindow_system_version = make_number (26); /* RE Emacs version */ + Vwindow_system_version = make_number (27); /* RE Emacs version */ tty->terminal->type = output_msdos_raw; /* If Emacs was dumped on DOS/V machine, forget the stale VRAM diff --git a/test/data/xdg/mimeapps.list b/test/data/xdg/mimeapps.list new file mode 100644 index 00000000000..27fbd94b16b --- /dev/null +++ b/test/data/xdg/mimeapps.list @@ -0,0 +1,9 @@ +[Default Applications] +x-test/foo=a.desktop + +[Added Associations] +x-test/foo=b.desktop +x-test/baz=a.desktop + +[Removed Associations] +x-test/foo=c.desktop;d.desktop diff --git a/test/data/xdg/mimeinfo.cache b/test/data/xdg/mimeinfo.cache new file mode 100644 index 00000000000..6e54f604fa0 --- /dev/null +++ b/test/data/xdg/mimeinfo.cache @@ -0,0 +1,4 @@ +[MIME Cache] +x-test/foo=c.desktop;d.desktop +x-test/bar=a.desktop;c.desktop +x-test/baz=b.desktop;d.desktop diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el index fc69919fbe1..7df2449b9eb 100644 --- a/test/lisp/electric-tests.el +++ b/test/lisp/electric-tests.el @@ -617,6 +617,12 @@ baz\"\"" :fixture-fn #'electric-quote-local-mode :test-in-comments nil :test-in-strings nil) +(define-electric-pair-test electric-quote-replace-double-disabled + "" "\"" :expected-string "\"" :expected-point 2 + :modes '(text-mode) + :fixture-fn #'electric-quote-local-mode + :test-in-comments nil :test-in-strings nil) + (define-electric-pair-test electric-quote-context-sensitive-backtick "" "`" :expected-string "`" :expected-point 2 :modes '(text-mode) @@ -638,6 +644,13 @@ baz\"\"" :bindings '((electric-quote-context-sensitive . t)) :test-in-comments nil :test-in-strings nil) +(define-electric-pair-test electric-quote-replace-double-bob + "" "\"" :expected-string "“" :expected-point 2 + :modes '(text-mode) + :fixture-fn #'electric-quote-local-mode + :bindings '((electric-quote-replace-double . t)) + :test-in-comments nil :test-in-strings nil) + (define-electric-pair-test electric-quote-context-sensitive-bol-single "a\n" "--'" :expected-string "a\n‘" :expected-point 4 :modes '(text-mode) @@ -652,6 +665,13 @@ baz\"\"" :bindings '((electric-quote-context-sensitive . t)) :test-in-comments nil :test-in-strings nil) +(define-electric-pair-test electric-quote-replace-double-bol + "a\n" "--\"" :expected-string "a\n“" :expected-point 4 + :modes '(text-mode) + :fixture-fn #'electric-quote-local-mode + :bindings '((electric-quote-replace-double . t)) + :test-in-comments nil :test-in-strings nil) + (define-electric-pair-test electric-quote-context-sensitive-after-space-single " " "-'" :expected-string " ‘" :expected-point 3 :modes '(text-mode) @@ -666,6 +686,13 @@ baz\"\"" :bindings '((electric-quote-context-sensitive . t)) :test-in-comments nil :test-in-strings nil) +(define-electric-pair-test electric-quote-replace-double-after-space + " " "-\"" :expected-string " “" :expected-point 3 + :modes '(text-mode) + :fixture-fn #'electric-quote-local-mode + :bindings '((electric-quote-replace-double . t)) + :test-in-comments nil :test-in-strings nil) + (define-electric-pair-test electric-quote-context-sensitive-after-letter-single "a" "-'" :expected-string "a’" :expected-point 3 :modes '(text-mode) @@ -680,6 +707,13 @@ baz\"\"" :bindings '((electric-quote-context-sensitive . t)) :test-in-comments nil :test-in-strings nil) +(define-electric-pair-test electric-quote-replace-double-after-letter + "a" "-\"" :expected-string "a”" :expected-point 3 + :modes '(text-mode) + :fixture-fn #'electric-quote-local-mode + :bindings '((electric-quote-replace-double . t)) + :test-in-comments nil :test-in-strings nil) + (define-electric-pair-test electric-quote-context-sensitive-after-paren-single "(" "-'" :expected-string "(‘" :expected-point 3 :modes '(text-mode) @@ -694,6 +728,13 @@ baz\"\"" :bindings '((electric-quote-context-sensitive . t)) :test-in-comments nil :test-in-strings nil) +(define-electric-pair-test electric-quote-replace-double-after-paren + "(" "-\"" :expected-string "(“" :expected-point 3 + :modes '(text-mode) + :fixture-fn #'electric-quote-local-mode + :bindings '((electric-quote-replace-double . t)) + :test-in-comments nil :test-in-strings nil) + ;; Simulate ‘markdown-mode’: it sets both ‘comment-start’ and ;; ‘comment-use-syntax’, but derives from ‘text-mode’. (define-electric-pair-test electric-quote-markdown-in-text diff --git a/test/lisp/xdg-tests.el b/test/lisp/xdg-tests.el index b80f5e85524..eaf03ab9a03 100644 --- a/test/lisp/xdg-tests.el +++ b/test/lisp/xdg-tests.el @@ -65,4 +65,16 @@ (should (equal (xdg-desktop-strings " ") nil)) (should (equal (xdg-desktop-strings "a; ;") '("a" " ")))) +(ert-deftest xdg-mime-associations () + "Test reading MIME associations from files." + (let* ((apps (expand-file-name "mimeapps.list" xdg-tests-data-dir)) + (cache (expand-file-name "mimeinfo.cache" xdg-tests-data-dir)) + (fs (list apps cache))) + (should (equal (xdg-mime-collect-associations "x-test/foo" fs) + '("a.desktop" "b.desktop"))) + (should (equal (xdg-mime-collect-associations "x-test/bar" fs) + '("a.desktop" "c.desktop"))) + (should (equal (xdg-mime-collect-associations "x-test/baz" fs) + '("a.desktop" "b.desktop" "d.desktop"))))) + ;;; xdg-tests.el ends here diff --git a/test/src/data-tests.el b/test/src/data-tests.el index 8de8c145d40..374d1689b9e 100644 --- a/test/src/data-tests.el +++ b/test/src/data-tests.el @@ -107,6 +107,21 @@ (should (isnan (min 1.0 0.0e+NaN))) (should (isnan (min 1.0 0.0e+NaN 1.1)))) +(defun data-tests-popcnt (byte) + "Calculate the Hamming weight of BYTE." + (if (< byte 0) + (setq byte (lognot byte))) + (setq byte (- byte (logand (lsh byte -1) #x55555555))) + (setq byte (+ (logand byte #x33333333) (logand (lsh byte -2) #x33333333))) + (lsh (* (logand (+ byte (lsh byte -4)) #x0f0f0f0f) #x01010101) -24)) + +(ert-deftest data-tests-logcount () + (should (cl-loop for n in (number-sequence -255 255) + always (= (logcount n) (data-tests-popcnt n)))) + ;; https://oeis.org/A000120 + (should (= 11 (logcount 9727))) + (should (= 8 (logcount 9999)))) + ;; Bool vector tests. Compactly represent bool vectors as hex ;; strings. |