Merge branch 'master' into feature/igc3

This commit is contained in:
Helmut Eller 2026-04-04 20:59:46 +02:00
commit 6eec001187
109 changed files with 3714 additions and 2591 deletions

View file

@ -868,13 +868,20 @@ otherwise stated, affects only the current Emacs session. The only
way to alter the variable in future sessions is to put something in
your initialization file (@pxref{Init File}).
If you're setting a customizable variable in your initialization
file, and you don't want to use the Customize interface, you can use
the @code{setopt} macro. For instance:
@findex setopt
If you're setting a customizable variable, and you don't want to use
the Customize interface, you can use the @code{setopt} macro. For
instance:
@example
(setopt fill-column 75)
M-: (setopt fill-column 75) @key{RET}
@end example
@noindent
Or, if you want to do this in your initialization file:
@example
(setopt fill-column 75)
@end example
This works the same as @code{setq}, but if the variable has any
@ -883,6 +890,34 @@ special setter functions, they will be run automatically when using
non-customizable variables, but this is less efficient than using
@code{setq}.
@findex setopt-local
There is also a buffer-local version of @code{setopt}, called
@code{setopt-local}, that you can use to set buffer specific values for
customizable options, for example, in mode hooks (@pxref{Hooks}).
This works the same as @code{setq-local}, but if the variable has any
special setter functions, they will be run automatically when using
@code{setopt-local}. You can also use @code{setopt-local} on other,
non-customizable variables, but this is less efficient than using
@code{setq-local}.
If you want to change the value of a customizable variable only in
your current buffer, you can use the @code{setopt-local} macro. For
instance:
@example
M-: (setopt-local fill-column 75) @key{RET}
@end example
@noindent
Or, if you want to do this in your initialization file, use the
following inside a mode hook so this variable will be automatically
customized in buffers of that mode (@pxref{Hooks}):
@example
(setopt-local fill-column 75)
@end example
@node Hooks
@subsection Hooks
@cindex hook
@ -3262,7 +3297,7 @@ acquainted with conventions from other programs.
The functionality enabled by the @code{newcomers-presets} theme will
change between releases of Emacs. We may add new functionality, and
also remove old functionality that we think has been superseded.
Therefore, if you get used to the newcomers' presets, consider copying
them into your own configuration and then disabling the theme again.
You can use the command @code{copy-theme-options} (@pxref{Custom
Themes}) to do this.
Therefore, if you get used to the newcomers' presets, you should copy
them into your own configuration and then disable the theme again. You
can use the command @code{copy-theme-options} (@pxref{Custom Themes}) to
do this.

View file

@ -2764,10 +2764,10 @@ Table}.)
@node Xref Commands
@subsubsection Commands Available in the @file{*xref*} Buffer
@cindex commands in @file{*xref*} buffers
@cindex XREF mode
@cindex Xref mode
The following commands are provided in the @file{*xref*} buffer by
the special XREF mode:
the special Xref mode:
@table @kbd
@item @key{RET}
@ -2880,7 +2880,7 @@ prompt always, customize the value of the variable
to prompt only if there's no usable identifier at point.) The command
then presents the @file{*xref*} buffer with all the references to the
identifier, showing the file name and the line where the identifier is
referenced. The XREF mode commands are available in this buffer, see
referenced. The Xref mode commands are available in this buffer, see
@ref{Xref Commands}.
When invoked in a buffer whose major mode uses the @code{etags} backend,
@ -2926,6 +2926,16 @@ matches of that regexp in the names of the identifiers with
@code{xref-query-replace-in-results}, but is more convenient when you
want to rename a single identifier specified by its name @var{from}.
@findex xref-change-to-xref-edit-mode
@cindex Xref Edit mode
@cindex mode, Xref Edit
Typing @kbd{e} in the @file{*xref*} buffer makes the buffer writable
and enters the Xref Edit mode. Similar to Occur Edit mode (@pxref{Other
Repeating Search}), you can edit the matching lines reported by
Xref backend and have those changes reflected in the buffer visiting the
originating file. Type @kbd{C-c C-c} to leave the Xref Edit mode and
return to the Xref mode.
@findex tags-search
@kbd{M-x tags-search} reads a regexp using the minibuffer, then
searches for matches in all the files in the selected tags table, one

View file

@ -14660,9 +14660,9 @@ beginning of the file. The function definition looks like this:
@smallexample
@group
(defun lengths-list-file (filename)
"Return list of definitions' lengths within FILE.
"Return list of definitions' lengths within the file named FILENAME.
The returned list is a list of numbers.
Each number is the number of words or
Each number in the list is the number of words or
symbols in one function definition."
@end group
@group
@ -14683,10 +14683,10 @@ symbols in one function definition."
@end smallexample
@noindent
The function is passed one argument, the name of the file on which it
will work. It has four lines of documentation, but no interactive
specification. Since people worry that a computer is broken if they
don't see anything going on, the first line of the body is a
The function is passed one argument @var{filename}, the name of the file
on which it will work. It has four lines of documentation, but no
interactive specification. Since people worry that a computer is broken
if they don't see anything going on, the first line of the body is a
message.
The next line contains a @code{save-excursion} that returns Emacs's
@ -14730,8 +14730,8 @@ definition and constructs a lengths' list containing the information.
Emacs kills the buffer after working through it. This is to save
space inside of Emacs. My version of GNU Emacs 19 contained over 300
source files of interest; GNU Emacs 22 contains over a thousand source
files. Another function will apply @code{lengths-list-file} to each
of the files.
files, and Emacs 30.2 more than 1600. Another function will apply
@code{lengths-list-file} to each of the files.
Finally, the last expression within the @code{let} expression is the
@code{lengths-list} variable; its value is returned as the value of
@ -14744,13 +14744,13 @@ C-e} (@code{eval-last-sexp}).
@c !!! 22.1.1 lisp sources location here
@smallexample
(lengths-list-file
"/usr/local/share/emacs/22.1/lisp/emacs-lisp/debug.el")
"/usr/local/share/emacs/30.2/lisp/emacs-lisp/debug.el")
@end smallexample
@noindent
You may need to change the pathname of the file; the one here is for
GNU Emacs version 22.1. To change the expression, copy it to
the @file{*scratch*} buffer and edit it.
You may need to change the name of the file; the one here is for default
installation tree of GNU Emacs version 30.2. To change the expression,
copy it to the @file{*scratch*} buffer and edit it.
@need 1200
@noindent
@ -14768,10 +14768,11 @@ Then evaluate the @code{lengths-list-file} expression.)
@need 1200
The lengths' list for @file{debug.el} takes less than a second to
produce and looks like this in GNU Emacs 22:
produce and looks like this in GNU Emacs 30.2:
@smallexample
(83 113 105 144 289 22 30 97 48 89 25 52 52 88 28 29 77 49 43 290 232 587)
(79 26 140 34 17 112 81 24 155 54 43 102 21 36 36 117 28 29 102 49 43
208 101 28 22 728 15 27)
@end smallexample
@need 1500

View file

@ -372,12 +372,15 @@ added by calls to @code{custom-add-frequent-value} (see below).
@item :set @var{setfunction}
Specify @var{setfunction} as the way to change the value of this
option when using the Customize interface. The function
@var{setfunction} should take two arguments, a symbol (the option
name) and the new value, and should do whatever is necessary to update
@var{setfunction} should take two or three arguments, a symbol (the option
name), the new value, and an optional @var{buffer-local} indicator.
@var{setfunction} should do whatever is necessary to update
the value properly for this option (which may not mean simply setting
the option as a Lisp variable); preferably, though, it should not
modify its value argument destructively. The default for
@var{setfunction} is @code{set-default-toplevel-value}.
modify its value argument destructively. If optional @var{buffer-local}
is non-nil, the new value should be set buffer locally and not affect its
global or default values. The default for @var{setfunction} is
@code{set-default-toplevel-value}.
If defined, @var{setfunction} will also be called when evaluating a
@code{defcustom} form with @kbd{C-M-x} in Emacs Lisp mode and when the
@ -387,7 +390,7 @@ If defined, @var{setfunction} will also be called when evaluating a
If you specify this keyword, the variable's documentation string
should describe how to do the same job in hand-written Lisp code,
either by invoking @var{setfunction} directly or by using
@code{setopt}.
@code{setopt} or @code{setopt-local}.
@kindex get@r{, @code{defcustom} keyword}
@item :get @var{getfunction}

View file

@ -1661,6 +1661,7 @@ Tips and Conventions
* Compilation Tips:: Making compiled code run fast.
* Warning Tips:: Turning off compiler warnings.
* Documentation Tips:: Writing readable documentation strings.
* Documentation Group Tips:: Writing useful documentation groups.
* Comment Tips:: Conventions for writing comments.
* Library Headers:: Standard headers for library packages.

View file

@ -2777,6 +2777,9 @@ the end of the file name.
If @var{text} is a string, @code{make-temp-file} inserts it in the file.
On Posix systems, Emacs creates the file with permissions that limit its
access to the current user.
To prevent conflicts among different libraries running in the same
Emacs, each Lisp program that uses @code{make-temp-file} should have its
own @var{prefix}. The number added to the end of @var{prefix}

View file

@ -89,6 +89,20 @@ displayed on that terminal; the list of possible values is the same as
for @code{framep} above.
@end defun
@defun frame-initial-p &optional frame
This predicate returns non-@code{nil} if @var{frame} is or holds the
initial text frame that is used internally during daemon mode
(@pxref{Initial Options, daemon,, emacs, The GNU Emacs Manual}), batch
mode (@pxref{Batch Mode}), and the early stages of startup
(@pxref{Startup Summary}). Interactive and graphical programs, for
instance, can use this predicate to avoid operating on the initial
frame, which is never displayed.
If @var{frame} is a terminal, this function returns non-@code{nil} if
@var{frame} holds the initial frame. If @var{frame} is omitted or
@code{nil}, it defaults to the selected one.
@end defun
@cindex top-level frame
On a graphical terminal we distinguish two types of frames: A normal
@dfn{top-level frame} is a frame whose window-system window is a child
@ -3029,7 +3043,7 @@ direction.
See also @code{next-window} and @code{previous-window}, in @ref{Cyclic
Window Ordering}.
Some Lisp programs need to find one or more frames that satisfy a
Some Lisp programs need to find one or more frames that satisfy
given criteria. The function @code{filtered-frame-list} is provided for
this purpose.

View file

@ -828,14 +828,16 @@ if the user types the help character again.
@cindex documentation groups
@cindex groups of functions
@cindex function groups
@cindex shortdoc groups
Emacs can list functions based on various groupings. For instance,
@code{string-trim} and @code{mapconcat} are ``string'' functions, so
@kbd{M-x shortdoc RET string RET} will give an overview
of functions that operate on strings.
@kbd{M-x shortdoc RET string RET} will give an overview of these and
other functions that operate on strings.
The documentation groups are created with the
@code{define-short-documentation-group} macro.
@code{define-short-documentation-group} macro. @xref{Documentation
Group Tips}, for how to write good documentation groups.
@defmac define-short-documentation-group group &rest functions
Define @var{group} as a group of functions, and provide short
@ -846,6 +848,7 @@ summaries of using those functions. The optional argument
(@var{func} [@var{keyword} @var{val}]@dots{})
@end lisp
@cindex documentation group keywords
The following keywords are recognized:
@table @code

View file

@ -35,6 +35,7 @@ in batch mode, e.g., with a command run by @kbd{@w{M-x compile
* Compilation Tips:: Making compiled code run fast.
* Warning Tips:: Turning off compiler warnings.
* Documentation Tips:: Writing readable documentation strings.
* Documentation Group Tips:: Writing useful documentation groups.
* Comment Tips:: Conventions for writing comments.
* Library Headers:: Standard headers for library packages.
@end menu
@ -934,6 +935,89 @@ If you do not anticipate anyone editing your code with older Emacs
versions, there is no need for this work-around.
@end itemize
@node Documentation Group Tips
@section Tips for Documentation Groups
@cindex documentation groups, tips
@cindex tips for documentation groups
@cindex documentation groups, compatibility
Documentation groups, available since Emacs 28, are useful to document
functions of Lisp packages based on various groupings
(@pxref{Documentation Groups}). This section gives some tips on how you
can define documentation groups in your Lisp package in a way such that
users of different Emacs versions can equally well use these groups.
@itemize @bullet
@item
To define documentation groups for your own Lisp package across
different Emacs versions, you can use a boilerplate template along the
lines of the following to make your package compile and load without
errors:
@smallexample
@group
;;; well-doc.el --- a well-documented package -*- lexical-binding: t; -*-
@dots{} package header and contents @dots{}
@end group
@group
;; Explicitly require shortdoc for Emacs 28, which does not have an
;; autoload for macro `define-short-documentation-group'. And for
;; Emacs 30, so that we can redefine `shortdoc--check' later.
(require 'shortdoc nil t)
(eval-when-compile
;; Default macro `define-short-documentation-group' for Emacs 27
;; and older, which do not have the shortdoc feature at all.
(unless (fboundp 'define-short-documentation-group)
(defmacro define-short-documentation-group (&rest _)))
;; Disable too rigid shortdoc checks for Emacs 30, which let it
;; error out on newer shortdoc keywords.
(when (eq emacs-major-version 30)
(fset 'shortdoc--check #'ignore)))
@end group
@group
(define-short-documentation-group well-doc
@dots{})
;;; well-doc.el ends here
@end group
@end smallexample
@findex define-short-documentation-group
If you do not intend to support some of the Emacs versions mentioned
above, you can safely omit the corresponding forms from the template.
If you intend to support only Emacs 31 and newer, you do not need any
of the above and can just use @code{define-short-documentation-group}.
@item
@cindex documentation group keywords, compatibility
Newer Emacs versions might introduce newer documentation group features
and keywords. However, these features or keywords will never break the
display of a documentation group in older Emacs versions. Suppose you
use a hypothetical group keyword @code{:super-pretty-print}, available
in some future Emacs version, like this in your Lisp package
@file{well-doc.el}:
@smallexample
@group
(define-short-documentation-group well-doc
(well-doc-foo
:eval (well-doc-foo)
:super-pretty-print t))
@end group
@end smallexample
That future Emacs version will then supposedly super-pretty-print the
example for function @code{well-doc-foo}. Older Emacs versions will
silently ignore keyword @code{:super-pretty-print} and show the example
according to their regular display rules.
@end itemize
@node Comment Tips
@section Tips on Writing Comments
@cindex comments, Lisp convention for

View file

@ -6728,6 +6728,45 @@ See the docstring of variable @code{tramp-methods} for possible
@code{foo-tramp-executable} in this example would be a Lisp constant,
which is the program name of @command{foo}.
If a parameter doesn't have a static value but must be computed at
runtime, a format specifier can be used, like @t{"%h"} in the example
above. See the docstring of @code{tramp-methods}, which patterns are
expanded in which parameter. Furthermore, other format specifiers can
be added via the variable @code{tramp-extra-expand-args}.
The following parameters expand format specifiers for the
@code{tramp-sh} backend: @code{tramp-copy-args},
@code{tramp-copy-env}, @code{tramp-copy-file-name},
@code{tramp-login-args}, @code{tramp-login-program},
@code{tramp-remote-copy-args}.
The example above could use
@lisp
(tramp-login-program "%1")
@end lisp
And you could set @code{tramp-extra-expand-args} as connection-local value:
@lisp
@group
(defun foo-tramp-get-login-program (vec)
"Return connection-local value of `tramp-login-program'."
@dots{})
@end group
@group
(connection-local-set-profile-variables
'foo-tramp-connection-local-default-profile
'((tramp-extra-expand-args
?1 (foo-tramp-get-login-program (car tramp-current-connection)))))
(connection-local-set-profiles
'(:application tramp :protocol "foo")
foo-tramp-connection-local-default-profile)
@end group
@end lisp
Another initialization could tell @value{tramp} which are the default
user and host name for method @option{foo}. This is done by calling
@code{tramp-set-completion-function}:

View file

@ -18,7 +18,16 @@ to look up issue github#1234, go to
https://github.com/joaotavora/eglot/issues/1234.
* Changes to upcoming Eglot
* Changes in Eglot 1.23 (2/4/2026)
** Unbreak ELPA Eglot (github#1584)
Broken due to bad 'jsonrpc.el' dependency.
** 'eglot-report-progress' can be safely set to 'messages' (bug#80653)
* Changes in Eglot 1.22 (1/4/2026)
** File watch limits to prevent resource exhaustion (github#1568)
@ -50,6 +59,19 @@ beneficial and helps servers avoid costly useless work.
Eglot now sets 'imenu-create-index-function' using ':override' advice,
making the integration cleaner and more predictable.
** Diagnostics from unopened files recalled on session start (github#1531)
Some servers (notably rust-analyzer) publish diagnostics for all
project files at startup and never republish them on 'didOpen'. Eglot
now saves such early diagnostics and reports them when those files are
subsequently opened.
** Changes to 'eglot-server-programs'
- new 'static-ls' for 'haskell-mode'
- new 'wat_server' for 'wat-mode' (WebAssembly Text) (bug#80188)
- new 'elp' replaces 'erlang_ls' for 'erlang-mode' (bug#79943)
** Fixed textDocument/prepareRename support (github#1554)
Eglot now properly checks server capabilities before sending

View file

@ -1760,6 +1760,15 @@ If 'page-delimiters' is set in 'whitespace-style', or the new minor mode
width of the window. The new 'whitespace-page-delimiter' face can be
used to customize the appearance.
---
*** New user option 'whitespace-global-mode-buffers'.
Normally, 'global-whitespace-mode' skips special buffers whose name
starts with an asterisk '*'. This user option provides an override: it
contains a list of regular expressions used to match the names of
special buffers in which 'global-whitespace-mode' should turn on. The
default value preserves the existing exception for the "*scratch*"
buffer.
** Bookmark
---
@ -2531,6 +2540,12 @@ of a literal newline. This prevents executing many Dired operations on
such a file from failing and signaling an error. The default value of
this user option is nil.
---
*** New Dired handling of errors from 'ls'.
When invoking a Dired command causes 'ls' to emit an error message,
Emacs now displays the message in a popped up buffer instead of
outputting it in the Dired buffer and signaling an error.
** Grep
+++
@ -3187,6 +3202,11 @@ This minor mode binds 'xref-find-definitions-at-mouse' to
definition, following the convention from other editors. The global
minor mode 'global-xref-mouse-mode' will enable this in all buffers.
+++
*** New command 'xref-change-to-xref-edit-mode'.
It's bound to "e" and it switches an Xref buffer into an "editable" mode
like similar features in Occur and Grep buffers.
** Revert
+++
@ -4092,6 +4112,14 @@ to display its char argument on a given frame. This new function,
unlike 'char-displayable-p', does not check whether the character can be
encoded by the underlying terminal.
+++
** New function 'frame-initial-p'.
This predicate returns non-nil if a given frame or terminal is or holds,
respectively, the initial text frame that is used internally during
daemon mode, batch mode, and the early stages of startup. Interactive
and graphical programs, for instance, can use this predicate to avoid
operating on the initial frame, which is never displayed.
+++
** New macros 'static-when' and 'static-unless'.
Like 'static-if', these macros evaluate their condition at
@ -4124,6 +4152,17 @@ change it globally with:
---
*** Loading a file displays a warning if there is no 'lexical-binding' cookie.
---
** New function 'set-local'.
This is the buffer local equivalent of the function 'set'.
+++
** New macro 'setopt-local'.
This is the buffer local version of 'setopt' for user options rather
than plain variables and uses 'custom-set'/'set-local' to set variable
values. A new argument, BUFFER-LOCAL, is passed to 'custom-set'
functions to indicate the buffer local context.
+++
** New macros 'incf' and 'decf'.
They increment or decrement the value stored in a variable (a symbol),
@ -4458,6 +4497,13 @@ singleton list.
* Changes in Emacs 31.1 on Non-Free Operating Systems
---
** Support macOS Accessibility Zoom focus tracking.
This is an important change for visually-impaired users. If macOS
Accessibility Zoom is enabled (System Settings, Accessibility, Zoom)
with keyboard focus tracking (Advanced...), Zoom is informed of updated
cursor positions during each redisplay cycle.
---
** Process execution has been optimized on Android.
The run-time performance of subprocesses on recent Android releases,

View file

@ -21,11 +21,20 @@
;;; Commentary
;; A theme that enables user options new users might be interested in.
;; The guideline to enabling a feature is "would this interest someone
;; who wouldn't even know that this option exists?". Please avoid
;; opinionated cosmetic changes, that is the job of regular/color-scheme
;; themes.
;; This theme configures user options that we can reasonably expect the
;; average, new user to want to enable, but would otherwise be unlikely
;; to discover on their own. This includes support for convenience
;; features, adjustment of default settings that are in place for
;; historical reasons, aiding discoverability (at the potential cost of
;; more visual noise) and trying and follow common conventions that
;; other editors have established over the past decades.
;; The goal is to help providing a better starting point for users who
;; would otherwise feel overwhelmed when first starting to use Emacs,
;; without having to burden existing users with invasive changes to
;; Emacs' default behavior. Options in the theme should NOT hinder
;; developing a better understanding of Emacs (e.g. enabling emulation
;; modes) or make opinionated cosmetic changes.
;;; Code:
@ -120,6 +129,7 @@ This minor mode will enable and disable the theme on startup."
'(indent-tabs-mode nil)
'(imenu-auto-rescan t)
'(view-read-only t)
'(column-number-mode t)
;;;; Directory managment-related options
'(dired-auto-revert-buffer t)
@ -153,7 +163,10 @@ This minor mode will enable and disable the theme on startup."
;;;; Frame- and window-related options
'(frame-inhibit-implied-resize t)
'(tab-bar-history-mode t)
'(tab-bar-show 0))
'(tab-bar-show 0)
;;;; Programming-related options
'(compilation-scroll-output 'first-error))
(provide-theme 'newcomers-presets)
;;; newcomers-presets-theme.el ends here

View file

@ -316,6 +316,11 @@ main (int argc, char **argv)
SCMP_A0_32 (SCMP_CMP_EQ, 0) /* pid == 0 (current process) */,
SCMP_A2_64 (SCMP_CMP_EQ, 0) /* new_limit == NULL */);
/* Allow reading the scheduler policy and affinity, so num_processors
can determine the number of usable CPUs. */
RULE0 (SCMP_ACT_ALLOW, SCMP_SYS (sched_getaffinity));
RULE0 (SCMP_ACT_ALLOW, SCMP_SYS (sched_getscheduler));
/* Block changing resource limits, but don't crash. */
RULE (SCMP_ACT_ERRNO (EPERM), SCMP_SYS (prlimit64),
SCMP_A0_32 (SCMP_CMP_EQ, 0) /* pid == 0 (current process) */,

View file

@ -85,6 +85,9 @@ HOST, USER, PORT, REQUIRE, and MAX."
((null host)
;; Do not build a result, as none will match when HOST is nil
nil)
((not (file-directory-p auth-source-pass-filename))
;; Do nothing if the password-store folder doesn't exist.
nil)
(auth-source-pass-extra-query-keywords
(auth-source-pass--build-result-many host port user require max))
(t

View file

@ -1084,7 +1084,7 @@ even if it doesn't match the type.)
\(fn [VARIABLE VALUE]...)"
(declare (debug setq))
(unless (evenp (length pairs))
(error "PAIRS must have an even number of variable/value members"))
(signal 'wrong-number-of-arguments (list 'setopt (length pairs))))
(let ((expr nil))
(while pairs
(unless (symbolp (car pairs))
@ -1100,11 +1100,53 @@ even if it doesn't match the type.)
;; Check that the type is correct.
(when-let* ((type (get variable 'custom-type)))
(unless (widget-apply (widget-convert type) :match value)
(warn "Value `%S' for variable `%s' does not match its type \"%s\""
value variable type)))
(warn "Value does not match %S's type `%S': %S" variable type value)))
(put variable 'custom-check-value (list value))
(funcall (or (get variable 'custom-set) #'set-default) variable value))
;;;###autoload
(defmacro setopt-local (&rest pairs)
"Set buffer local VARIABLE/VALUE pairs, and return the final VALUE.
This is like `setq-local', but is meant for user options instead of
plain variables. This means that `setopt-local' will execute any
`custom-set' form associated with VARIABLE. Unlike `setopt',
`setopt-local' does not affect a user option's global value.
Note that `setopt-local' will emit a warning if the type of a VALUE does
not match the type of the corresponding VARIABLE as declared by
`defcustom'. (VARIABLE will be assigned the value even if it doesn't
match the type.)
Signal an error if a `custom-set' form does not support the
`buffer-local' argument.
\(fn [VARIABLE VALUE]...)"
(declare (debug setq))
(unless (evenp (length pairs))
(signal 'wrong-number-of-arguments (list 'setopt-local (length pairs))))
(let ((expr nil))
(while pairs
(unless (symbolp (car pairs))
(error "Attempting to set a non-symbol: %s" (car pairs)))
(push `(setopt--set-local ',(car pairs) ,(cadr pairs))
expr)
(setq pairs (cddr pairs)))
(macroexp-progn (nreverse expr))))
;;;###autoload
(defun setopt--set-local (variable value)
(custom-load-symbol variable)
;; Check that the type is correct.
(when-let* ((type (get variable 'custom-type)))
(unless (widget-apply (widget-convert type) :match value)
(warn "Value does not match %S's type `%S': %S" variable type value)))
(condition-case _
(funcall (or (get variable 'custom-set)
(lambda (x v &optional _) (set-local x v)))
variable value 'buffer-local)
(wrong-number-of-arguments
(error "The setter of %S does not support setopt-local" variable))))
;;;###autoload
(defun customize-save-variable (variable value &optional comment)
"Set the default for VARIABLE to VALUE, and save it for future sessions.

View file

@ -398,7 +398,11 @@ then it searches *all* buffers."
;; Set it so `dabbrev-capf' won't reset the vars.
(setq dabbrev--last-abbrev-location (point-marker))
(let ((completion-at-point-functions '(dabbrev-capf)))
(completion-at-point)))
(unless (completion-at-point)
(user-error "No dynamic expansion for \"%s\" found%s"
(dabbrev--abbrev-at-point)
(if dabbrev--check-other-buffers
"" " in this-buffer")))))
(defun dabbrev-capf ()
"Dabbrev completion function for `completion-at-point-functions'."

View file

@ -775,6 +775,7 @@ if different)."
;; Don't delete daemon's initial frame, or
;; we'll never be able to close the last
;; client's frame (Bug#26912).
;; Use `frame-initial-p'?
(and (daemonp) (eq frame terminal-frame))
(frame-parameter frame 'desktop-dont-clear))
(delete-frame frame))
@ -1067,9 +1068,8 @@ DIRNAME must be the directory in which the desktop file will be saved."
(and (not (frame-parameter frame 'desktop-dont-save))
;; Don't save daemon initial frames, since we cannot (and don't
;; need to) restore them.
(not (and (daemonp)
(equal (terminal-name (frame-terminal frame))
"initial_terminal")))))
(not (and (daemonp) ;; FIXME: Remove `daemonp'?
(frame-initial-p frame)))))
(defconst desktop--app-id `(desktop . ,desktop-file-version))
@ -1260,7 +1260,7 @@ This function also sets `desktop-dirname' to nil."
"True if calling `desktop-restore-frameset' will actually restore it."
(and desktop-restore-frames desktop-saved-frameset
;; Don't restore frames when the selected frame is the daemon's
;; initial frame.
;; initial frame. Use `frame-initial-p'?
(not (and (daemonp) (eq (selected-frame) terminal-frame)))
t))

View file

@ -649,6 +649,10 @@ The match starts at the beginning of the line and ends after the end
of the line.
Subexpression 2 must end right before the \\n.")
(defvar dired--ls-error-buffer nil
"Non-nil if the current dired invocation yields an `ls' error.
The non-nil value is the buffer containing the error message.")
;;; Faces
@ -1230,7 +1234,16 @@ Type \\[describe-mode] after entering Dired for more info.
If DIRNAME is already in a Dired buffer, that buffer is used without refresh."
;; Cannot use (interactive "D") because of wildcards.
(interactive (dired-read-dir-and-switches ""))
(pop-to-buffer-same-window (dired-noselect dirname switches)))
(prog1 (pop-to-buffer-same-window (dired-noselect dirname switches))
(dired--display-ls-error)))
;; This is needed to let clicks on the menu bar invoke Dired even if
;; some feature remaps the Dired command to another command.
;;;###autoload
(defun dired-from-menubar (dirname &optional switches)
"Edit an existing directory."
(interactive (dired-read-dir-and-switches ""))
(dired dirname switches))
;;;###autoload (keymap-set ctl-x-4-map "d" #'dired-other-window)
;;;###autoload
@ -1240,21 +1253,24 @@ If this command needs to split the current window, it by default obeys
the user options `split-height-threshold' and `split-width-threshold',
when it decides whether to split the window horizontally or vertically."
(interactive (dired-read-dir-and-switches "in other window "))
(switch-to-buffer-other-window (dired-noselect dirname switches)))
(prog1 (switch-to-buffer-other-window (dired-noselect dirname switches))
(dired--display-ls-error)))
;;;###autoload (keymap-set ctl-x-5-map "d" #'dired-other-frame)
;;;###autoload
(defun dired-other-frame (dirname &optional switches)
"\"Edit\" directory DIRNAME. Like `dired' but make a new frame."
(interactive (dired-read-dir-and-switches "in other frame "))
(switch-to-buffer-other-frame (dired-noselect dirname switches)))
(prog1 (switch-to-buffer-other-frame (dired-noselect dirname switches))
(dired--display-ls-error)))
;;;###autoload (keymap-set tab-prefix-map "d" #'dired-other-tab)
;;;###autoload
(defun dired-other-tab (dirname &optional switches)
"\"Edit\" directory DIRNAME. Like `dired' but make a new tab."
(interactive (dired-read-dir-and-switches "in other tab "))
(switch-to-buffer-other-tab (dired-noselect dirname switches)))
(prog1 (switch-to-buffer-other-tab (dired-noselect dirname switches))
(dired--display-ls-error)))
;;;###autoload
(defun dired-noselect (dir-or-list &optional switches)
@ -1439,10 +1455,19 @@ The return value is the target column for the file names."
(let ((failed t))
(unwind-protect
(progn (dired-readin)
(setq failed nil))
;; dired-readin can fail if parent directories are inaccessible.
;; Don't leave an empty buffer around in that case.
(if failed (kill-buffer buffer))))
;; Check for file entries (they are listed below the
;; directory name and (if present) wildcard lines).
(while (and (skip-syntax-forward "\s")
(looking-at "\\(.+:$\\|wildcard\\)"))
(forward-line))
(unless (eobp)
(setq failed nil)))
;; No file entries indicates an `ls' error, and `dired-readin'
;; can fail if parent directories are inaccessible. In either
;; case don't leave the Dired buffer around.
(when failed
(kill-buffer buffer)
(setq buffer nil))))
(goto-char (point-min))
(dired-initial-position dirname))
(when (consp dired-directory)
@ -4003,20 +4028,11 @@ Considers buffers closer to the car of `buffer-list' to be more recent."
(not (memq buffer1 (memq buffer2 (buffer-list))))))
(defun dired--filename-with-newline-p ()
"Check if a file name in this directory has a newline.
Return non-nil if at least one file name in this directory contains
either a literal newline or the string \"\\n\")."
(save-excursion
(goto-char (point-min))
(catch 'found
(while (not (eobp))
(when (dired-move-to-filename)
(let ((fn (buffer-substring-no-properties
(point) (dired-move-to-end-of-filename))))
(when (or (memq 10 (seq-into fn 'list))
(string-search "\\n" fn))
(throw 'found t))))
(forward-line)))))
"Check whether a file name in this directory has a newline.
Return non-nil if at least one file name in this directory contains a
newline character (regardless of whether Dired displays the character as
a literal newline or as \"\\n\")."
(directory-files default-directory nil "\n"))
(defun dired--remove-b-switch ()
"Remove all variants of the `b' switch from `dired-actual-switches'.
@ -4094,6 +4110,13 @@ See `%s' for other alternatives and more information."))
(set-window-point (get-buffer-window)
(search-backward "Warning (dired)")))))
(defun dired--display-ls-error ()
"Pop up a buffer displaying the current `ls' error, if any."
(when dired--ls-error-buffer
(let* ((errwin (display-buffer dired--ls-error-buffer)))
(fit-window-to-buffer errwin))
(setq dired--ls-error-buffer nil)))
;;; Deleting files

View file

@ -102,6 +102,7 @@ See Info node `Displaying Boundaries' for details."
(defun display-fill-column-indicator--turn-on ()
"Turn on `display-fill-column-indicator-mode'."
(unless (or (minibufferp)
;; Use `frame-initial-p'?
(and (daemonp) (eq (selected-frame) terminal-frame)))
(display-fill-column-indicator-mode)))

View file

@ -1901,6 +1901,8 @@ See Info node `(elisp) Integer Basics'."
sqlite-available-p sqlitep
;; syntax.c
standard-syntax-table syntax-table syntax-table-p
;; terminal.c
frame-initial-p
;; thread.c
current-thread
;; timefns.c

View file

@ -195,8 +195,7 @@ the debugger will not be entered."
;; backtrace to stdout. This happens for example while
;; handling an error in code from early-init.el with
;; --debug-init.
(and (eq t (framep (selected-frame)))
(equal "initial_terminal" (terminal-name)))))
(frame-initial-p)))
;; Don't let `inhibit-message' get in our way (especially important if
;; `non-interactive-frame' evaluated to a non-nil value.
(inhibit-message nil)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -372,6 +372,7 @@ entirely by setting `warning-suppress-types' or
(if (bolp)
(forward-char -1))
(message "%s" (buffer-substring start (point))))))
;; Use `frame-initial-p'?
((and (daemonp) (eq (selected-frame) terminal-frame))
;; Display daemon startup warnings on the first client frame.
(letrec ((afterfun

View file

@ -232,7 +232,22 @@ encryption is used."
(epa-file-decode-and-insert
string file visit beg end replace))))
(if visit
(set-visited-file-modtime))))
(set-visited-file-modtime)))
;; The decoded file could still need another massage from a
;; file name handler, for example a file like
;; "folder.sym.tar.gz.gpg". (Bug#80641)
(when (find-file-name-handler
(file-name-sans-extension file)
'insert-file-contents)
(let ((tmpfile
(make-temp-file
nil nil
(file-name-extension (file-name-base file) 'period))))
(let (file-name-handler-alist) (write-region nil nil tmpfile))
(erase-buffer)
(insert-file-contents tmpfile)
(setq length (- (point-max) (point-min)))
(delete-file tmpfile))))
(if (and local-copy
(file-exists-p local-copy))
(delete-file local-copy)))

View file

@ -1006,7 +1006,7 @@ Failing that, choose the first face in both NEW-FACES and NORMALS."
(dolist (candidate (cdr ranks))
(when (and (not (equal candidate choice))
(gethash candidate (car new-faces))
(gethash choice normals))
(gethash candidate normals))
(throw 'face candidate)))
;; Otherwise, go with any "normal" face other than
;; `choice' in the region.

View file

@ -1693,11 +1693,18 @@ time `erc-mode-hook' runs for any connection."
(declare (indent 1))
(cl-assert (stringp (car args)))
(if (derived-mode-p 'erc-mode)
(unless (or (erc-with-server-buffer ; needs `erc-server-process'
(apply #'erc-button--display-error-notice-with-keys
(current-buffer) args)
t)
erc--target) ; unlikely
(unless
(or (erc-with-server-buffer ; needs `erc-server-process'
(let ((fn
(lambda (buffer)
(erc-with-buffer (buffer)
(apply #'erc-button--display-error-notice-with-keys
buffer args)))))
(if erc--msg-props
(run-at-time nil nil fn (current-buffer))
(funcall fn (current-buffer))))
t)
erc--target) ; unlikely
(let (hook)
(setq hook
(lambda (_)

View file

@ -1790,7 +1790,10 @@ If DIR-FLAG is non-nil, create a new empty directory instead of a file.
If SUFFIX is non-nil, add that at the end of the file name.
If TEXT is a string, insert it into the new file; DIR-FLAG should be nil.
Otherwise the file will be empty."
Otherwise the file will be empty.
On Posix systems, the file/directory is created with access mode bits
that limit access to the current user."
(let ((absolute-prefix
(if (or (zerop (length prefix)) (member prefix '("." "..")))
(concat (file-name-as-directory temporary-file-directory) prefix)
@ -8320,41 +8323,24 @@ Valid wildcards are `*', `?', `[abc]' and `[a-z]'."
(forward-line -1))
(if (let ((case-fold-search nil)) (looking-at "//DIRED//"))
(let ((end (line-end-position))
(linebeg (point))
error-lines)
;; Find all the lines that are error messages,
;; and record the bounds of each one.
(goto-char beg)
(while (< (point) linebeg)
(or (eql (following-char) ?\s)
(push (list (point) (line-end-position)) error-lines))
(forward-line 1))
(setq error-lines (nreverse error-lines))
;; Now read the numeric positions of file names.
(linebeg (point)))
;; Read the numeric positions of file names.
(goto-char linebeg)
(forward-word-strictly 1)
(forward-char 3)
(while (< (point) end)
(let ((start (insert-directory-adj-pos
(+ beg (read (current-buffer)))
error-lines))
(end (insert-directory-adj-pos
(+ beg (read (current-buffer)))
error-lines)))
(if (memq (char-after end) '(?\n ?\s ?/ ?* ?@ ?% ?= ?|))
;; End is followed by \n or by output of -F.
(put-text-property start end 'dired-filename t)
;; It seems that we can't trust ls's output as to
;; byte positions of filenames.
(put-text-property beg (point) 'dired-filename nil)
(end-of-line))))
(let ((start (+ beg (read (current-buffer))))
(end (+ beg (read (current-buffer)))))
(when (memq (char-after end) '(?\n ?\s ?/ ?* ?@ ?% ?= ?|))
;; End is followed by \n or by output of -F.
(put-text-property start end 'dired-filename t))))
(goto-char end)
(beginning-of-line)
(delete-region (point) (progn (forward-line 1) (point))))
;; Take care of the case where the ls output contains a
;; "//DIRED-OPTIONS//"-line, but no "//DIRED//"-line
;; and we went one line too far back (see above).
(forward-line 1))
(unless (bobp) (forward-line 1)))
(if (let ((case-fold-search nil)) (looking-at "//DIRED-OPTIONS//"))
(delete-region (point) (progn (forward-line 1) (point))))))
@ -8363,12 +8349,12 @@ Valid wildcards are `*', `?', `[abc]' and `[a-z]'."
;; FULL-DIRECTORY-P is nil.
;; The single line of output must display FILE's name as it was
;; given, namely, an absolute path name.
;; - must insert exactly one line for each file if WILDCARD or
;; - must insert exactly one entry for each file if WILDCARD or
;; FULL-DIRECTORY-P is t, plus one optional "total" line
;; before the file lines, plus optional text after the file lines.
;; Lines are delimited by "\n", so filenames containing "\n" are not
;; allowed.
;; File lines should display the basename.
;; Entries are delimited by "\n", but file names containing "\n" are
;; allowed and by default the "\n" is displayed as a literal newline.
;; File entries should display the basename.
;; - must be consistent with
;; - functions dired-move-to-filename, (these two define what a file line is)
;; dired-move-to-end-of-filename,
@ -8410,10 +8396,10 @@ normally equivalent short `-D' option is just passed on to
(declare-function ls-lisp--insert-directory "ls-lisp")
(ls-lisp--insert-directory file switches wildcard full-directory-p))
(t
(let (result (beg (point)))
(let ((beg (point))
(errfile (make-temp-file "lserr")))
;; Read the actual directory using `insert-directory-program'.
;; RESULT gets the status code.
(let* (;; We at first read by no-conversion, then after
;; putting text property `dired-filename, decode one
;; bunch by one to preserve that property.
@ -8423,143 +8409,88 @@ normally equivalent short `-D' option is just passed on to
(and enable-multibyte-characters
(or file-name-coding-system
default-file-name-coding-system))))
(setq result
(if wildcard
;; If the wildcard is just in the file part, then run ls in
;; the directory part of the file pattern using the last
;; component as argument. Otherwise, run ls in the longest
;; subdirectory of the directory part free of wildcards; use
;; the remaining of the file pattern as argument.
(let* ((dir-wildcard (insert-directory-wildcard-in-dir-p file))
(default-directory
(cond (dir-wildcard (car dir-wildcard))
(t
(if (file-name-absolute-p file)
(file-name-directory file)
(file-name-directory (expand-file-name file))))))
(pattern (if dir-wildcard (cdr dir-wildcard) (file-name-nondirectory file))))
;; NB since switches is passed to the shell, be
;; careful of malicious values, eg "-l;reboot".
;; See eg dired-safe-switches-p.
(call-process
shell-file-name nil t nil
shell-command-switch
(concat (if (memq system-type '(ms-dos windows-nt))
""
"\\") ; Disregard Unix shell aliases!
insert-directory-program
" -d "
;; Quote switches that require quoting
;; such as "--block-size='1". But don't
;; quote switches that use patterns
;; such as "--ignore=PATTERN" (bug#71935).
(mapconcat #'shell-quote-wildcard-pattern
(if (stringp switches)
(split-string-and-unquote switches)
switches)
" ")
" -- "
;; Quote some characters that have
;; special meanings in shells; but
;; don't quote the wildcards--we want
;; them to be special. We also
;; currently don't quote the quoting
;; characters in case people want to
;; use them explicitly to quote
;; wildcard characters.
(shell-quote-wildcard-pattern pattern))))
;; SunOS 4.1.3, SVr4 and others need the "." to list the
;; directory if FILE is a symbolic link.
(unless full-directory-p
(setq switches
(cond
((stringp switches) (concat switches " -d"))
((member "-d" switches) switches)
(t (append switches '("-d"))))))
(if (string-match "\\`~" file)
(setq file (expand-file-name file)))
(apply #'call-process
insert-directory-program nil t nil
(append
(if (listp switches) switches
(unless (equal switches "")
;; Split the switches at any spaces so we can
;; pass separate options as separate args.
(split-string-and-unquote switches)))
;; Avoid lossage if FILE starts with `-'.
'("--")
(list file))))))
(if wildcard
;; If the wildcard is just in the file part, then run ls in
;; the directory part of the file pattern using the last
;; component as argument. Otherwise, run ls in the longest
;; subdirectory of the directory part free of wildcards; use
;; the remaining of the file pattern as argument.
(let* ((dir-wildcard
(insert-directory-wildcard-in-dir-p file))
(default-directory
(cond (dir-wildcard (car dir-wildcard))
(t
(if (file-name-absolute-p file)
(file-name-directory file)
(file-name-directory
(expand-file-name file))))))
(pattern (if dir-wildcard
(cdr dir-wildcard)
(file-name-nondirectory file))))
;; NB since switches is passed to the shell, be
;; careful of malicious values, eg "-l;reboot".
;; See eg dired-safe-switches-p.
(call-process
shell-file-name nil (list t errfile) nil
shell-command-switch
(concat (if (memq system-type '(ms-dos windows-nt))
""
"\\") ; Disregard Unix shell aliases!
insert-directory-program
" -d "
;; Quote switches that require quoting
;; such as "--block-size='1". But don't
;; quote switches that use patterns
;; such as "--ignore=PATTERN" (bug#71935).
(mapconcat #'shell-quote-wildcard-pattern
(if (stringp switches)
(split-string-and-unquote switches)
switches)
" ")
" -- "
;; Quote some characters that have
;; special meanings in shells; but
;; don't quote the wildcards--we want
;; them to be special. We also
;; currently don't quote the quoting
;; characters in case people want to
;; use them explicitly to quote
;; wildcard characters.
(shell-quote-wildcard-pattern pattern))))
;; SunOS 4.1.3, SVr4 and others need the "." to list the
;; directory if FILE is a symbolic link.
(unless full-directory-p
(setq switches
(cond
((stringp switches) (concat switches " -d"))
((member "-d" switches) switches)
(t (append switches '("-d"))))))
(if (string-match "\\`~" file)
(setq file (expand-file-name file)))
(apply #'call-process
insert-directory-program nil (list t errfile) nil
(append
(if (listp switches) switches
(unless (equal switches "")
;; Split the switches at any spaces so we can
;; pass separate options as separate args.
(split-string-and-unquote switches)))
;; Avoid lossage if FILE starts with `-'.
'("--")
(list file)))))
;; If we got "//DIRED//" in the output, it means we got a real
;; directory listing, even if `ls' returned nonzero.
;; So ignore any errors.
(when (if (stringp switches)
(string-match "--dired\\>" switches)
(member "--dired" switches))
(save-excursion
(let ((case-fold-search nil))
(forward-line -2)
(when (looking-at "//SUBDIRED//")
(forward-line -1))
(if (looking-at "//DIRED//")
(setq result 0)))))
;; If `ls' emits an error message, copy it to a buffer that will
;; be displayed when a Dired invocation results in the `ls'
;; error.
(when (> (file-attribute-size (file-attributes errfile)) 0)
(defvar dired--ls-error-buffer) ; Pacify byte-compiler.
(let ((errbuf (get-buffer-create "*ls error*")))
(with-current-buffer errbuf
(erase-buffer)
(insert-file-contents errfile))
(setq dired--ls-error-buffer errbuf)))
(delete-file errfile)
(when (and (not (eq 0 result))
(eq insert-directory-ls-version 'unknown))
;; The first time ls returns an error,
;; find the version numbers of ls,
;; and set insert-directory-ls-version
;; to > if it is more than 5.2.1, < if it is less, nil if it
;; is equal or if the info cannot be obtained.
;; (That can mean it isn't GNU ls.)
(let ((version-out
(with-temp-buffer
(call-process "ls" nil t nil "--version")
(buffer-string))))
(setq insert-directory-ls-version
(if (string-match "ls (.*utils) \\([0-9.]*\\)$" version-out)
(let* ((version (match-string 1 version-out))
(split (split-string version "[.]"))
(numbers (mapcar #'string-to-number split))
(min '(5 2 1))
comparison)
(while (and (not comparison) (or numbers min))
(cond ((null min)
(setq comparison #'>))
((null numbers)
(setq comparison #'<))
((> (car numbers) (car min))
(setq comparison #'>))
((< (car numbers) (car min))
(setq comparison #'<))
(t
(setq numbers (cdr numbers)
min (cdr min)))))
(or comparison #'=))
nil))))
;; For GNU ls versions 5.2.2 and up, ignore minor errors.
(when (and (eq 1 result) (eq insert-directory-ls-version #'>))
(setq result 0))
;; If `insert-directory-program' failed, signal an error.
(unless (eq 0 result)
;; Delete the error message it may have output.
(delete-region beg (point))
;; On non-Posix systems, we cannot open a directory, so
;; don't even try, because that will always result in
;; the ubiquitous "Access denied". Instead, show the
;; command line so the user can try to guess what went wrong.
(if (and (file-directory-p file)
(memq system-type '(ms-dos windows-nt)))
(error
"Reading directory: \"%s %s -- %s\" exited with status %s"
insert-directory-program
(if (listp switches) (concat switches) switches)
file result)
;; Unix. Access the file to get a suitable error.
(access-file file "Reading directory")
(error "Listing directory failed but `access-file' worked")))
(insert-directory-clean beg switches)
;; Now decode what read if necessary.
(let ((coding (or coding-system-for-read
@ -8594,18 +8525,6 @@ normally equivalent short `-D' option is just passed on to
(put-text-property pos (point)
'dired-filename t))))))))))))
(defun insert-directory-adj-pos (pos error-lines)
"Convert `ls --dired' file name position value POS to a buffer position.
File name position values returned in ls --dired output
count only stdout; they don't count the error messages sent to stderr.
So this function converts to them to real buffer positions.
ERROR-LINES is a list of buffer positions of error message lines,
of the form (START END)."
(while (and error-lines (< (caar error-lines) pos))
(setq pos (+ pos (- (nth 1 (car error-lines)) (nth 0 (car error-lines)))))
(pop error-lines))
pos)
(defun insert-directory-safely (file switches
&optional wildcard full-directory-p)
"Insert directory listing for FILE, formatted according to SWITCHES.

View file

@ -493,6 +493,7 @@ there (in decreasing order of priority)."
(setq parms (append initial-frame-alist window-system-frame-alist
default-frame-alist parms nil))
;; Don't enable tab-bar in daemon's initial frame.
;; Use `frame-initial-p'?
(when (and (daemonp) (eq (selected-frame) terminal-frame))
(setq parms (delq (assq 'tab-bar-lines parms) parms)))
parms))

View file

@ -1370,12 +1370,10 @@ All keyword parameters default to nil."
;; frame, as that would only trigger
;; warnings.
(not
(and (daemonp)
(equal (terminal-name (frame-terminal
frame))
"initial_terminal"))))
(delete-frame frame)))
cleanup-frames)))
(and (daemonp) ;; FIXME: Remove `daemonp'?
(frame-initial-p frame))))
(delete-frame frame)))
cleanup-frames)))
(maphash (lambda (frame _action) (push frame map)) frameset--action-map)
(dolist (frame (sort map
;; Minibufferless frames must go first to avoid

View file

@ -70,6 +70,9 @@ DELAY is a string, giving the length of the time. Possible values are:
* YYYY-MM-DD for a specific date. The time of day is given by the
variable `gnus-delay-default-hour', minute and second are zero.
* YYYY-MM-DD hh:mm(:ss) for a specific date and time. If seconds are left
out, they will be zero.
* hh:mm for a specific time. Use 24h format. If it is later than this
time, then the deadline is tomorrow, else today.
@ -82,8 +85,21 @@ generated when the article is sent."
message-mode)
;; Allow spell checking etc.
(run-hooks 'message-send-hook)
(let (num unit year month day hour minute deadline) ;; days
(let (num unit year month day hour minute deadline second) ;; days
(cond ((string-match
"\\([0-9][0-9][0-9]?[0-9]?\\)-\\([0-9]+\\)-\\([0-9]+\\) \\([0-9]\\{1,2\\}\\):\\([0-9]\\{2\\}\\):?\\([0-9]\\{2\\}\\)?"
delay)
(setq year (string-to-number (match-string 1 delay))
month (string-to-number (match-string 2 delay))
day (string-to-number (match-string 3 delay))
hour (string-to-number (match-string 4 delay))
minute (string-to-number (match-string 5 delay))
second (if (match-string 6 delay) (string-to-number (match-string 6 delay)) 0))
(setq deadline
(message-make-date
(encode-time second minute hour
day month year))))
((string-match
"\\([0-9][0-9][0-9]?[0-9]?\\)-\\([0-9]+\\)-\\([0-9]+\\)"
delay)
(setq year (string-to-number (match-string 1 delay))

View file

@ -36,6 +36,10 @@
;;; Code:
(require 'icalendar)
(require 'icalendar-parser)
(eval-when-compile (require 'icalendar-macs))
(require 'icalendar-ast)
(require 'icalendar-utils)
(require 'eieio)
(require 'gmm-utils)
(require 'mm-decode)
@ -82,8 +86,8 @@
:type (or null t))
(recur :initarg :recur
:accessor gnus-icalendar-event:recur
:initform ""
:type (or null string))
:initform nil
:type (or null list))
(uid :initarg :uid
:accessor gnus-icalendar-event:uid
:type string)
@ -127,295 +131,212 @@
(cl-defmethod gnus-icalendar-event:recurring-freq ((event gnus-icalendar-event))
"Return recurring frequency of EVENT."
(let ((rrule (gnus-icalendar-event:recur event)))
(string-match "FREQ=\\([[:alpha:]]+\\)" rrule)
(match-string 1 rrule)))
(ical:recur-freq (gnus-icalendar-event:recur event)))
(cl-defmethod gnus-icalendar-event:recurring-interval ((event gnus-icalendar-event))
"Return recurring interval of EVENT."
(let ((rrule (gnus-icalendar-event:recur event))
(default-interval "1"))
(if (string-match "INTERVAL=\\([[:digit:]]+\\)" rrule)
(match-string 1 rrule)
default-interval)))
(ical:recur-interval-size (gnus-icalendar-event:recur event)))
(cl-defmethod gnus-icalendar-event:recurring-days ((event gnus-icalendar-event))
"Return, when available, the week day numbers on which the EVENT recurs."
(let ((rrule (gnus-icalendar-event:recur event))
(weekday-map '(("SU" . 0)
("MO" . 1)
("TU" . 2)
("WE" . 3)
("TH" . 4)
("FR" . 5)
("SA" . 6))))
(when (and rrule (string-match "BYDAY=\\([^;]+\\)" rrule))
(let ((bydays (split-string (match-string 1 rrule) ",")))
(seq-map
(lambda (x) (cdr (assoc x weekday-map)))
(seq-filter (lambda (x) (string-match "^[A-Z]\\{2\\}$" x)) bydays))))))
(let ((rrule (gnus-icalendar-event:recur event)))
(when rrule
(mapcar (lambda (el) (if (consp el) (car el) el))
(ical:recur-by* 'BYDAY rrule)))))
(cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
(format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event)))
(defun gnus-icalendar-event--decode-datefield (event field zone-map)
(let* ((dtdate (icalendar--get-event-property event field))
(dtdate-zone (icalendar--find-time-zone
(icalendar--get-event-property-attributes
event field) zone-map))
(dtdate-dec (icalendar--decode-isodatetime dtdate nil dtdate-zone)))
(when dtdate-dec (encode-time dtdate-dec))))
(defun gnus-icalendar-event--find-attendee (attendees ids)
"Return the first `icalendar-attendee' in ATTENDEES matching IDS.
IDS should be a list of strings. The first attendee is returned whose
name (as `icalendar-cnparam') or email address (without \"mailto:\")
is a member of IDS."
(catch 'found
(dolist (attendee attendees)
(ical:with-property attendee ((ical:cnparam :value name))
(let ((email (ical:strip-mailto value)))
(when (or (member name ids)
(member email ids))
(throw 'found attendee)))))))
(defun gnus-icalendar-event--find-attendee (ical name-or-email)
(let* ((event (car (icalendar--all-events ical)))
(event-props (caddr event)))
(cl-labels ((attendee-name (att) (plist-get (cadr att) 'CN))
(attendee-email
(att)
(replace-regexp-in-string "^.*MAILTO:" "" (caddr att)))
(attendee-prop-matches-p
(prop)
(and (eq (car prop) 'ATTENDEE)
(or (member (attendee-name prop) name-or-email)
(let ((att-email (attendee-email prop)))
(gnus-icalendar-find-if
(lambda (str-or-fun)
(if (functionp str-or-fun)
(funcall str-or-fun att-email)
(string-match str-or-fun att-email)))
name-or-email))))))
(gnus-icalendar-find-if #'attendee-prop-matches-p event-props))))
(defun gnus-icalendar-event--attendees-by-type (attendees)
"Return lists of required and optional participants in ATTENDEES.
ATTENDEES must be a list of `icalendar-attendee' nodes. The returned
list has the form (REQUIRED OPTIONAL), where each is a list of
`icalendar-attendee' nodes."
(let (required optional)
(dolist (attendee attendees)
(ical:with-property attendee ((ical:roleparam :value role))
(when (or (null role) ; "REQ-PARTICIPANT" is the default
(equal role "REQ-PARTICIPANT"))
(push attendee required))
(when (equal role "OPT-PARTICIPANT")
(push attendee optional))))
(list (nreverse required)
(nreverse optional))))
(defun gnus-icalendar-event--get-attendee-names (ical)
(let* ((event (car (icalendar--all-events ical)))
(attendee-props (seq-filter
(lambda (p) (eq (car p) 'ATTENDEE))
(caddr event))))
(defun gnus-icalendar-event-from-ical (vcalendar &optional ids)
"Initialize an event instance with the first `icalendar-vevent' in VCALENDAR.
IDS should be a list of strings representing names and email addresses
by which to identify an `icalendar-attendee' in the event as the
recipient."
(ical:with-component vcalendar
((ical:vevent vevent)
(ical:method :value method))
(ical:with-component vevent
((ical:organizer :value organizer)
(ical:attendee :all attendees)
(ical:summary :value summary)
(ical:description :value description)
(ical:dtstart :value dtstart)
(ical:dtend :value dtend)
(ical:location :value location)
(ical:rrule :value rrule)
(ical:uid :value uid))
(cl-labels
((attendee-role (prop)
;; RFC5546: default ROLE is REQ-PARTICIPANT
(and prop
(or (plist-get (cadr prop) 'ROLE)
"REQ-PARTICIPANT")))
(attendee-name
(prop)
(or (plist-get (cadr prop) 'CN)
(replace-regexp-in-string "^.*MAILTO:" "" (caddr prop))))
(attendees-by-type (type)
(seq-filter
(lambda (p) (string= (attendee-role p) type))
attendee-props))
(attendee-names-by-type
(type)
(mapcar #'attendee-name (attendees-by-type type))))
(list
(attendee-names-by-type "REQ-PARTICIPANT")
(attendee-names-by-type "OPT-PARTICIPANT")))))
(defun gnus-icalendar-event-from-ical (ical &optional attendee-name-or-email)
(let* ((event (car (icalendar--all-events ical)))
(organizer (replace-regexp-in-string
"^.*MAILTO:" ""
(or (icalendar--get-event-property event 'ORGANIZER) "")))
(prop-map '((summary . SUMMARY)
(description . DESCRIPTION)
(location . LOCATION)
(recur . RRULE)
(uid . UID)))
(method (caddr (assoc 'METHOD (caddr (car (nreverse ical))))))
(attendee (when attendee-name-or-email
(gnus-icalendar-event--find-attendee
ical attendee-name-or-email)))
(attendee-names (gnus-icalendar-event--get-attendee-names ical))
(let* ((attendee (when ids (gnus-icalendar-event--find-attendee attendees ids)))
(rsvp-p (ical:with-param-of attendee 'ical:rsvpparam))
;; RFC5546: default ROLE is REQ-PARTICIPANT
(role (and attendee
(or (plist-get (cadr attendee) 'ROLE)
"REQ-PARTICIPANT")))
(role (when attendee
(or (ical:with-param-of attendee 'ical:roleparam)
"REQ-PARTICIPANT")))
(participation-type (pcase role
("REQ-PARTICIPANT" 'required)
("OPT-PARTICIPANT" 'optional)
(_ 'non-participant)))
(zone-map (icalendar--convert-all-timezones ical))
(req/opt (gnus-icalendar-event--attendees-by-type attendees))
(args
(list :method method
:organizer organizer
:start-time (gnus-icalendar-event--decode-datefield
event 'DTSTART zone-map)
:end-time (gnus-icalendar-event--decode-datefield
event 'DTEND zone-map)
:rsvp (string= (plist-get (cadr attendee) 'RSVP) "TRUE")
:organizer (when organizer (ical:strip-mailto organizer))
:summary summary
:description description
:location location
:recur rrule
:start-time (encode-time dtstart)
:end-time (encode-time dtend)
:rsvp rsvp-p
:participation-type participation-type
:req-participants (car attendee-names)
:opt-participants (cadr attendee-names)))
(event-class
(cond
((string= method "REQUEST") 'gnus-icalendar-event-request)
((string= method "CANCEL") 'gnus-icalendar-event-cancel)
((string= method "REPLY") 'gnus-icalendar-event-reply)
(t 'gnus-icalendar-event))))
(cl-labels
((map-property
(prop)
(let ((value (icalendar--get-event-property event prop)))
(when value
;; ugly, but cannot get
;;replace-regexp-in-string work with "\\" as
;;REP, plus we should also handle "\\;"
(string-replace
"\\," ","
(string-replace
"\\n" "\n" (substring-no-properties value))))))
(accumulate-args
(mapping)
(cl-destructuring-bind (slot . ical-property) mapping
(setq args (append (list
(intern (concat ":" (symbol-name slot)))
(map-property ical-property))
args)))))
(mapc #'accumulate-args prop-map)
(apply
#'make-instance
event-class
(cl-loop for slot in (eieio-class-slots event-class)
for keyword = (intern
(format ":%s" (eieio-slot-descriptor-name slot)))
when (plist-member args keyword)
append (list keyword
(if (eq keyword :uid)
;; The UID has to be a string.
(or (plist-get args keyword) "")
(plist-get args keyword))))))))
:req-participants (car req/opt)
:opt-participants (cadr req/opt)
:uid (or uid ""))) ; UID must be a string
(event-class (pcase method
("REQUEST" 'gnus-icalendar-event-request)
("CANCEL" 'gnus-icalendar-event-cancel)
("REPLY" 'gnus-icalendar-event-reply)
(_ 'gnus-icalendar-event))))
;; Initialize and return the instance:
(apply
#'make-instance
event-class
(cl-loop for slot in (eieio-class-slots event-class)
for keyword = (intern
(format ":%s" (eieio-slot-descriptor-name slot)))
when (plist-member args keyword)
append (list keyword (plist-get args keyword))))))))
(defun gnus-icalendar-event-from-buffer (buf &optional attendee-name-or-email)
(defun gnus-icalendar-event-from-buffer (buf &optional ids)
"Parse RFC5545 iCalendar in buffer BUF and return an event object.
Return a gnus-icalendar-event object representing the first event
contained in the invitation. Return nil for calendars without an
event entry.
ATTENDEE-NAME-OR-EMAIL is a list of strings that will be matched
against the event's attendee names and emails. Invitation rsvp
status will be retrieved from the first matching attendee record."
(let ((ical (with-current-buffer (icalendar--get-unfolded-buffer (get-buffer buf))
(goto-char (point-min))
(icalendar--read-element nil nil))))
(when ical
(gnus-icalendar-event-from-ical ical attendee-name-or-email))))
IDS is a list of strings that identify the recipient
`icalendar-attendee' by name or email address. Invitation rsvp status
will be retrieved from the first matching attendee record."
(let ((vcalendar (ical:parse buf)))
(when vcalendar
(gnus-icalendar-event-from-ical vcalendar ids))))
;;;
;;; gnus-icalendar-event-reply
;;;
(defun gnus-icalendar-event--build-reply-event-body (ical-request status identities &optional comment)
(defun gnus-icalendar-event--build-reply (vcalendar status ids &optional comment)
"Return an `icalendar-vcalendar' based on VCALENDAR with updated STATUS.
STATUS should one of \\='accepted, \\='declined, or \\='tentative. The
recipient whose participation status is updated to STATUS is identified
in EVENT by finding an `icalendar-attendee' whose name or email address
matches one of the strings in IDS. If no such attendee is found, a new
`icalendar-attendee' is added from the values of `user-mail-address' and
`user-full-name'. COMMENT, if provided, will be added as an
`icalendar-comment' to the returned event."
(let ((summary-status (capitalize (symbol-name status)))
(attendee-status (upcase (symbol-name status)))
reply-event-lines)
(cl-labels
((update-summary
(line)
(if (string-match "^[^:]+:" line)
(replace-match (format "\\&%s: " summary-status) t nil line)
line))
(update-comment
(line)
(if comment (format "COMMENT:%s" comment)
line))
(update-dtstamp ()
(format-time-string "DTSTAMP:%Y%m%dT%H%M%SZ" nil t))
(attendee-matches-identity
(line)
(gnus-icalendar-find-if (lambda (name) (string-match-p name line))
identities))
(update-attendee-status
(line)
(when (and (attendee-matches-identity line)
(string-match "\\(PARTSTAT=\\)[^;]+" line))
(replace-match (format "\\1%s" attendee-status) t nil line)))
(process-event-line
(line)
(when (string-match "^\\([^;:]+\\)" line)
(let* ((key (match-string 0 line))
;; NOTE: not all of the below fields are mandatory,
;; but they are often present in other clients'
;; replies. Can be helpful for debugging, too.
(new-line
(cond
((string= key "ATTENDEE") (update-attendee-status line))
((string= key "SUMMARY") (update-summary line))
((string= key "COMMENT") (update-comment line))
((string= key "DTSTAMP") (update-dtstamp))
((member key '("ORGANIZER" "DTSTART" "DTEND"
"LOCATION" "DURATION" "SEQUENCE"
"RECURRENCE-ID" "UID"))
line)
(t nil))))
(when new-line
(push new-line reply-event-lines))))))
recipient)
(ical:with-component vcalendar
((ical:vtimezone :all tz-nodes)
(ical:vevent :first vevent))
(ical:with-component vevent
((ical:summary :value summary)
(ical:attendee :all attendees)
(ical:uid :value uid)
(ical:comment :value old-comment)
;; The nodes below are copied unchanged to the reply. Not all
;; of them are mandatory, but they are often present in other
;; clients' replies. Can be helpful for debugging, too.
(ical:organizer :first organizer-node)
(ical:dtstart :first dtstart-node)
(ical:dtend :first dtend-node)
(ical:duration :first duration-node)
(ical:location :first location-node)
(ical:sequence :first sequence-node)
(ical:recurrence-id :first recid-node))
(mapc #'process-event-line (split-string ical-request "\n"))
(setq recipient (gnus-icalendar-event--find-attendee attendees ids))
(if recipient
(ical:with-property recipient
((ical:partstatparam :first partstat-node))
(ical:ast-node-set-value partstat-node attendee-status))
;; RFC5546 refers to uninvited attendees as "party crashers".
;; This situation is common if the invitation is sent to a group
;; of people via a mailing list.
(lwarn 'gnus-icalendar :warning
"Could not find a matching event attendee; creating new.")
(setq recipient
(ical:make-property ical:attendee
(concat "mailto:" user-mail-address)
(ical:partstatparam attendee-status)
(ical:cnparam user-full-name)))
(push recipient attendees))
;; RFC5546 refers to uninvited attendees as "party crashers".
;; This situation is common if the invitation is sent to a group
;; of people via a mailing list.
(unless (gnus-icalendar-find-if (lambda (x) (string-match "^ATTENDEE" x))
reply-event-lines)
(lwarn 'gnus-icalendar :warning
"Could not find an event attendee matching given identity")
(push (format "ATTENDEE;RSVP=TRUE;PARTSTAT=%s;CN=%s:MAILTO:%s"
attendee-status user-full-name user-mail-address)
reply-event-lines))
;; Build the reply:
(ical:make-vcalendar
(ical:method "REPLY")
(@ tz-nodes)
(ical:vevent
(ical:uid uid)
recid-node
sequence-node
organizer-node
dtstart-node
dtend-node
duration-node
location-node
(ical:summary
(if (string-match "^[^:]+:" summary)
(replace-match (format "\\&%s: " summary-status) t nil summary)
summary))
(ical:comment (or comment old-comment))
(@ attendees)))))))
;; add comment line if not existing
(when (and comment
(not (gnus-icalendar-find-if
(lambda (x)
(string-match "^COMMENT" x))
reply-event-lines)))
(push (format "COMMENT:%s" comment) reply-event-lines))
(mapconcat #'identity `("BEGIN:VEVENT"
,@(nreverse reply-event-lines)
"END:VEVENT")
"\n"))))
(defun gnus-icalendar-event-reply-from-buffer (buf status identities &optional comment)
(defun gnus-icalendar-event-reply-from-buffer (buf status ids
&optional comment)
"Build a calendar event reply for request contained in BUF.
The reply will have STATUS (`accepted', `tentative' or `declined').
The reply will be composed for attendees matching any entry
on the IDENTITIES list.
Optional argument COMMENT will be placed in the comment field of the
reply.
"
(cl-labels
((extract-block
(blockname)
(save-excursion
(let ((block-start-re (format "^BEGIN:%s" blockname))
(block-end-re (format "^END:%s" blockname))
start)
(when (re-search-forward block-start-re nil t)
(setq start (line-beginning-position))
(re-search-forward block-end-re)
(buffer-substring-no-properties start (line-end-position)))))))
(let (zone event)
(with-current-buffer (icalendar--get-unfolded-buffer (get-buffer buf))
(goto-char (point-min))
(setq zone (extract-block "VTIMEZONE")
event (extract-block "VEVENT")))
(when event
(let ((contents (list "BEGIN:VCALENDAR"
"METHOD:REPLY"
"PRODID:Gnus"
"VERSION:2.0"
zone
(gnus-icalendar-event--build-reply-event-body event status identities comment)
"END:VCALENDAR")))
(mapconcat #'identity (delq nil contents) "\n"))))))
The reply will have STATUS (`accepted', `tentative' or `declined'). The
reply will be composed for attendees matching any entry in the
IDS list. Optional argument COMMENT will be placed in the
comment field of the reply."
(let (vcalendar reply)
(with-current-buffer (ical:unfolded-buffer-from-buffer (get-buffer buf))
(setq vcalendar (ical:parse))
(unless vcalendar
(error "Could not parse invitation; see buffer %s"
(buffer-name (ical:error-buffer))))
(setq reply
(gnus-icalendar-event--build-reply vcalendar status ids comment))
(ical:print-calendar-node reply))))
;;;
;;; gnus-icalendar-org
@ -455,15 +376,17 @@ reply.
"Return `org-mode' timestamp repeater string for recurring EVENT.
Return nil for non-recurring EVENT."
(when (gnus-icalendar-event:recurring-p event)
(let* ((freq-map '(("HOURLY" . "h")
("DAILY" . "d")
("WEEKLY" . "w")
("MONTHLY" . "m")
("YEARLY" . "y")))
(org-freq (cdr (assoc (gnus-icalendar-event:recurring-freq event) freq-map))))
(let* ((freq-map '((HOURLY . "h")
(DAILY . "d")
(WEEKLY . "w")
(MONTHLY . "m")
(YEARLY . "y")))
(org-freq
(alist-get (gnus-icalendar-event:recurring-freq event) freq-map))
(interval-size (gnus-icalendar-event:recurring-interval event)))
(when org-freq
(format "+%s%s" (gnus-icalendar-event:recurring-interval event) org-freq)))))
(format "+%d%s" interval-size org-freq)))))
(defun gnus-icalendar--find-day (start-date end-date day)
(let ((time-1-day 86400))
@ -550,7 +473,18 @@ Return nil for non-recurring EVENT."
(defun gnus-icalendar--format-participant-list (participants)
(mapconcat #'identity participants ", "))
"Format PARTICIPANTS as a comma-separated list.
Each `icalendar-attendee' in PARTICIPANTS will be represented like
A. Person <a.person@example.domain>
or simply: <a.person@example.domain>, if no `icalendar-cnparam' is present."
(mapconcat
(lambda (attendee)
(ical:with-property attendee ((ical:cnparam :value cn))
(if cn
(format "%s <%s>" cn value)
(format "<%s>" value))))
participants ", "))
;; TODO: make the template customizable
(cl-defmethod gnus-icalendar-event->org-entry ((event gnus-icalendar-event) reply-status)
@ -1110,3 +1044,7 @@ means prompt for a comment to include in the reply."
(provide 'gnus-icalendar)
;;; gnus-icalendar.el ends here
;; Local Variables:
;; read-symbol-shorthands: (("ical:" . "icalendar-"))
;; End:

View file

@ -2356,11 +2356,13 @@ ARGLIST can also be t or a string of the form \"(FUN ARG1 ARG2 ...)\"."
"Return a formal argument list for the function DEF.
If PRESERVE-NAMES is non-nil, return a formal arglist that uses
the same names as used in the original source code, when possible."
(let ((orig-def def)
;; Advice wrappers have "catch all" args, so fetch the actual underlying
;; function to find the real arguments.
(def (advice--cd*r
(indirect-function def)))) ;; Follow aliases to other symbols.
(let ((orig-def def))
(let ((seen nil))
;; Advice wrappers have "catch all" args, so fetch the actual underlying
;; function to find the real arguments. Also follow aliases.
(while (not (memq def seen))
(push def seen)
(setq def (advice--cd*r (indirect-function def)))))
;; If definition is a macro, find the function inside it.
(if (eq (car-safe def) 'macro) (setq def (cdr def)))
(cond

View file

@ -1897,8 +1897,10 @@ of NODENAME; if none is found it then tries a case-insensitive match
(if (equal nodename "") "Top" nodename) nil strict-case)))
(defun Info-goto-node-web (node)
"Use `browse-url' to go to the gnu.org web server's version of NODE.
By default, go to the current Info node."
"Use `browse-url' to go to the gnu.org Web server's version of NODE.
By default, go to the URL corresponding to the current Info node.
This uses `Info-url-for-node' to determine the URL that corresponds to NODE."
(interactive (list (Info-read-node-name
"Go to node (default current page): " Info-current-node))
Info-mode)
@ -1924,7 +1926,10 @@ By default, go to the current Info node."
(defun Info-url-for-node (node)
"Return the URL corresponding to NODE.
NODE should be a string of the form \"(manual)Node\"."
NODE should be a string of the form \"(manual)Node\".
The correspondence between Info manuals and their Web URLs is
established by `Info-url-alist', which see."
;; GNU Texinfo skips whitespaces and newlines between the closing
;; parenthesis and the node-name, i.e. space, tab, line feed and
;; carriage return.

View file

@ -1782,15 +1782,15 @@ Setup `char-width-table' appropriate for non-CJK language environment."
(let ((c0-acronyms '("NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL"
"BS" nil nil "VT" "FF" "CR" "SO" "SI"
"DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB"
"CAN" "EM" "SUB" "ESC" "FC" "GS" "RS" "US")))
"CAN" "EM" "SUB" "ESC" "FS" "GS" "RS" "US")))
(dotimes (i 32)
(aset char-acronym-table i (car c0-acronyms))
(setq c0-acronyms (cdr c0-acronyms))))
(let ((c1-acronyms '("PAD" "HOP" "BPH" "NBH" "IND" "NEL" "SSA" "ESA"
"HTS" "HTJ" "VTS" "PLD" "PLU" "R1" "SS2" "SS1"
"HTS" "HTJ" "VTS" "PLD" "PLU" "RI" "SS2" "SS3"
"DCS" "PU1" "PU2" "STS" "CCH" "MW" "SPA" "EPA"
"SOS" "SGCI" "SC1" "CSI" "ST" "OSC" "PM" "APC")))
"SOS" "SGCI" "SCI" "CSI" "ST" "OSC" "PM" "APC")))
(dotimes (i 32)
(aset char-acronym-table (+ #x0080 i) (car c1-acronyms))
(setq c1-acronyms (cdr c1-acronyms))))

View file

@ -155,9 +155,13 @@ and also consults the `emoji-alternate-names' alist."
;;;###autoload
(defun emoji-list ()
"List emojis and allow selecting and inserting one of them.
"List Emoji and allow selecting and inserting one of them.
If you are displaying Emoji on a text-only terminal, and some
of them look incorrect, or there are display artifacts when
scrolling the display, turn off `auto-composition-mode'.
Select the emoji by typing \\<emoji-list-mode-map>\\[emoji-list-select] on its picture.
The glyph will be inserted into the buffer that was current
The selected glyph will be inserted into the buffer that was current
when the command was invoked."
(interactive)
(let ((buf (current-buffer)))

View file

@ -4,7 +4,7 @@
;; Author: João Távora <joaotavora@gmail.com>
;; Keywords: processes, languages, extensions
;; Version: 1.0.27
;; Version: 1.0.28
;; Package-Requires: ((emacs "25.2"))
;; This is a GNU ELPA :core package. Avoid functionality that is not

View file

@ -219,7 +219,7 @@ macro to be executed before appending to it."
;;;###autoload (autoload 'kmacro-keymap "kmacro" "Keymap for keyboard macro commands." t 'keymap)
(if kmacro-call-mouse-event
(global-set-key (vector kmacro-call-mouse-event) #'kmacro-end-call-mouse))
(global-set-key (vector kmacro-call-mouse-event) #'kmacro-end-and-call-macro))
;;; Called from keyboard-quit
@ -742,8 +742,8 @@ With numeric ARG, repeat the macro that many times,
counting the definition just completed as the first repetition.
An argument of zero means repeat until error."
(interactive "p")
;; Isearch may push the kmacro-end-macro key sequence onto the macro.
;; Just ignore it when executing the macro.
;; Isearch may push the kmacro-end-macro key sequence onto the macro.
;; Just ignore it when executing the macro. FIXME: When?Why?
(unless executing-kbd-macro
(end-kbd-macro arg #'kmacro-loop-setup-function)
(when (and last-kbd-macro (= (length last-kbd-macro) 0))
@ -880,35 +880,25 @@ With \\[universal-argument], call second macro in macro ring."
;;;###autoload
(defun kmacro-end-and-call-macro (arg &optional no-repeat)
(defun kmacro-end-and-call-macro (arg &optional no-repeat event)
"Call last keyboard macro, ending it first if currently being defined.
With numeric prefix ARG, repeat macro that many times.
Zero argument means repeat until there is an error.
If triggered via a mouse EVENT, moves point to the position clicked
with the mouse before calling the macro.
To give a macro a name, so you can call it even after defining other
macros, use \\[kmacro-name-last-macro]."
(interactive "p")
(interactive (list current-prefix-arg nil
(if (consp last-input-event) last-input-event)))
(if defining-kbd-macro
(kmacro-end-macro nil))
(if event (mouse-set-point event))
(kmacro-call-macro arg no-repeat))
;;;###autoload
(defun kmacro-end-call-mouse (event)
"Move point to the position clicked with the mouse and call last kbd macro.
If kbd macro currently being defined end it before activating it."
(interactive "e")
(when defining-kbd-macro
(end-kbd-macro)
(when (and last-kbd-macro (= (length last-kbd-macro) 0))
(setq last-kbd-macro nil)
(message "Ignore empty macro")
;; Don't call `kmacro-ring-empty-p' to avoid its messages.
(while (and (null last-kbd-macro) kmacro-ring)
(kmacro-pop-ring1))))
(mouse-set-point event)
(kmacro-call-macro nil t))
(define-obsolete-function-alias 'kmacro-end-call-mouse
#'kmacro-end-and-call-macro "31.1")
;;; Misc. commands

View file

@ -27,13 +27,22 @@
;;; Code:
(defgroup korean nil
"Options for writing Korean."
:version "31.1"
:group 'languages)
;;;###autoload
(defvar default-korean-keyboard
(defcustom default-korean-keyboard
(if (string-search "3" (or (getenv "HANGUL_KEYBOARD_TYPE") ""))
"3"
"")
"The kind of Korean keyboard for Korean (Hangul) input method.
\"\" for 2, \"3\" for 3, and \"3f\" for 3f.")
\"\" for 2, \"3\" for 3, and \"3f\" for 3f."
:initialize #'custom-initialize-delay
:group 'korean
:version "31.1"
:type 'string)
;; functions useful for Korean text input

View file

@ -231,8 +231,8 @@ in the tool bar will close the current window where possible."
'(menu-item "Open Project Directory" project-dired
:enable (menu-bar-non-minibuffer-window-p)
:help "Read the root directory of the current project, to operate on its files"))
(define-key menu [dired]
'(menu-item "Open Directory..." dired
(define-key menu [open-directory]
'(menu-item "Open Directory..." dired-from-menubar
:enable (menu-bar-non-minibuffer-window-p)
:help "Read a directory, to operate on its files"))
(define-key menu [project-open-file]
@ -2287,7 +2287,7 @@ this frame."
(and menu-bar-close-window
(window-parent (selected-window)))))
(put 'dired 'menu-enable '(menu-bar-non-minibuffer-window-p))
(put 'dired-from-menubar 'menu-enable '(menu-bar-non-minibuffer-window-p))
;; Permit deleting frame if it would leave a visible or iconified frame.
(defun delete-frame-enabled-p ()
@ -2496,8 +2496,7 @@ It must accept a buffer as its only required argument.")
;; Ignore the initial frame if present. It can happen if
;; Emacs was started as a daemon. (bug#53740)
(dolist (frame (frame-list))
(unless (equal (terminal-name (frame-terminal frame))
"initial_terminal")
(unless (frame-initial-p frame)
(push frame frames)))
;; Make the menu of buffers proper.
(setq buffers-menu

View file

@ -2807,7 +2807,7 @@ has been requested by the completion table."
"Update displayed *Completions* buffer after change in buffer contents."
(if (not (or (minibufferp nil t) completion-in-region-mode))
(remove-hook 'after-change-functions #'completions--after-change t)
(when-let* ((window (get-buffer-window "*Completions*" 0)))
(when-let* ((window (get-buffer-window "*Completions*" 'visible)))
(when completion-auto-deselect
(with-selected-window window
(completions--deselect))))
@ -3480,7 +3480,7 @@ in the minibuffer window."
(defun minibuffer--completions-visible ()
"Return the window where the current *Completions* buffer is visible, if any."
(when-let* ((window (get-buffer-window "*Completions*" 0)))
(when-let* ((window (get-buffer-window "*Completions*" 'visible)))
(let ((reference-buffer
(buffer-local-value 'completion-reference-buffer
(window-buffer window))))

View file

@ -870,7 +870,8 @@ t if it successfully authenticates, nil otherwise."
(base64-encode-string
(format "\000%s\000%s"
(imap-quote-specials user)
(imap-quote-specials passwd)))))))))
(imap-quote-specials passwd))
t)))))))
(defun imap-anonymous-p (_buffer)
t)

View file

@ -451,21 +451,13 @@ Emacs dired can't find files."
(defun tramp-adb-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for Tramp files."
(tramp-skeleton-file-name-all-completions filename directory
(all-completions
filename
(with-parsed-tramp-file-name (expand-file-name directory) nil
(with-tramp-file-property v localname "file-name-all-completions"
(when (tramp-adb-do-ls v "-a" localname)
(mapcar
(lambda (f)
(if (file-directory-p (expand-file-name f directory))
(file-name-as-directory f)
f))
(with-current-buffer (tramp-get-buffer v)
(mapcar
(lambda (l)
(and (not (string-match-p (rx bol (* blank) eol) l)) l))
(split-string (buffer-string) "\n" 'omit))))))))))
(with-parsed-tramp-file-name (expand-file-name directory) nil
(when (tramp-adb-do-ls v "-a" localname)
(with-current-buffer (tramp-get-buffer v)
(mapcar
(lambda (l)
(and (not (string-match-p (rx bol (* blank) eol) l)) l))
(split-string (buffer-string) "\n" 'omit)))))))
(defun tramp-adb-handle-file-local-copy (filename)
"Like `file-local-copy' for Tramp files."

View file

@ -266,7 +266,7 @@ BODY is the backend specific code."
tramp--last-hop-directory)
tramp-compat-temporary-file-directory))
(program (let ((tramp-verbose 0))
(tramp-get-method-parameter
(tramp-expand-args
(make-tramp-file-name :method ,method)
'tramp-login-program)))
(vec (when (tramp-tramp-file-p default-directory)
@ -656,10 +656,9 @@ see its function help for a description of the format."
'((tramp-config-check . tramp-kubernetes--current-context-data)
;; This variable will be eval'ed in `tramp-expand-args'.
(tramp-extra-expand-args
. (?a (tramp-kubernetes--container (car tramp-current-connection))
?h (tramp-kubernetes--pod (car tramp-current-connection))
?x (tramp-kubernetes--context-namespace
(car tramp-current-connection)))))
?a (tramp-kubernetes--container (car tramp-current-connection))
?h (tramp-kubernetes--pod (car tramp-current-connection))
?x (tramp-kubernetes--context-namespace (car tramp-current-connection))))
"Default connection-local variables for remote kubernetes connections.")
(connection-local-set-profile-variables

View file

@ -741,18 +741,16 @@ absolute file names."
(defun tramp-crypt-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for Tramp files."
(tramp-skeleton-file-name-all-completions filename directory
(all-completions
filename
(let* (completion-regexp-list
tramp-crypt-enabled
(directory (file-name-as-directory directory))
(enc-dir (tramp-crypt-encrypt-file-name directory)))
(mapcar
(lambda (x)
(substring
(tramp-crypt-decrypt-file-name (concat enc-dir x))
(length directory)))
(file-name-all-completions "" enc-dir))))))
(let* (completion-regexp-list
tramp-crypt-enabled
(directory (file-name-as-directory directory))
(enc-dir (tramp-crypt-encrypt-file-name directory)))
(mapcar
(lambda (x)
(substring
(tramp-crypt-decrypt-file-name (concat enc-dir x))
(length directory)))
(file-name-all-completions "" enc-dir)))))
(defun tramp-crypt-handle-file-readable-p (filename)
"Like `file-readable-p' for Tramp files."

View file

@ -49,7 +49,7 @@ present for backward compatibility."
(let ((a1 (rassq 'ange-ftp-hook-function file-name-handler-alist))
(a2 (rassq 'ange-ftp-completion-hook-function file-name-handler-alist)))
(setq file-name-handler-alist
(delete a1 (delete a2 file-name-handler-alist)))))
(seq-difference file-name-handler-alist (list a1 a2)))))
(with-eval-after-load 'ange-ftp
(tramp-disable-ange-ftp))

View file

@ -102,10 +102,7 @@
"Like `file-name-all-completions' for Tramp files."
(tramp-skeleton-file-name-all-completions filename directory
(tramp-fuse-remove-hidden-files
(all-completions
filename
(file-name-all-completions
filename (tramp-fuse-local-file-name directory))))))
(file-name-all-completions "" (tramp-fuse-local-file-name directory)))))
;; This function isn't used.
(defun tramp-fuse-handle-insert-directory

View file

@ -1479,19 +1479,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
(defun tramp-gvfs-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for Tramp files."
(tramp-skeleton-file-name-all-completions filename directory
(unless (string-search "/" filename)
(all-completions
filename
(with-parsed-tramp-file-name (expand-file-name directory) nil
(with-tramp-file-property v localname "file-name-all-completions"
(let (result)
;; Get a list of directories and files.
(dolist (item
(tramp-gvfs-get-directory-attributes directory)
result)
(if (string-equal (cdr (assoc "type" item)) "directory")
(push (file-name-as-directory (car item)) result)
(push (car item) result))))))))))
(mapcar #'car (tramp-gvfs-get-directory-attributes directory))))
(defun tramp-gvfs-handle-file-notify-add-watch (file-name flags _callback)
"Like `file-notify-add-watch' for Tramp files."
@ -1545,11 +1533,13 @@ If FILE-SYSTEM is non-nil, return file system attributes."
(when rest-string
(tramp-message proc 10 "Previous string:\n%s" rest-string))
(tramp-message proc 6 "%S\n%s" proc string)
(setq string (concat rest-string string)
;; Fix action names.
string (string-replace "attributes changed" "attribute-changed" string)
string (string-replace "changes done" "changes-done-hint" string)
string (string-replace "renamed to" "moved" string))
(setq string
(thread-last
(concat rest-string string)
;; Fix action names.
(string-replace "attributes changed" "attribute-changed")
(string-replace "changes done" "changes-done-hint")
(string-replace "renamed to" "moved")))
;; https://bugs.launchpad.net/bugs/1742946
(when
(string-match-p

View file

@ -1993,48 +1993,39 @@ ID-FORMAT valid values are `string' and `integer'."
"Like `file-name-all-completions' for Tramp files."
(tramp-skeleton-file-name-all-completions filename directory
(with-parsed-tramp-file-name (expand-file-name directory) nil
(when (and (not (string-search "/" filename))
(tramp-connectable-p v))
(unless (string-search "/" filename)
(all-completions
filename
(with-tramp-file-property v localname "file-name-all-completions"
(let (result)
;; Get a list of directories and files, including
;; reliably tagging the directories with a trailing "/".
;; Because I rock. --daniel@danann.net
(if (tramp-get-remote-perl v)
(tramp-maybe-send-script
v tramp-perl-file-name-all-completions
"tramp_perl_file_name_all_completions")
(tramp-maybe-send-script
v tramp-shell-file-name-all-completions
"tramp_shell_file_name_all_completions"))
(let (result)
;; Get a list of directories and files, including reliably
;; tagging the directories with a trailing "/".
;; Because I rock. --daniel@danann.net
(if (tramp-get-remote-perl v)
(tramp-maybe-send-script
v tramp-perl-file-name-all-completions
"tramp_perl_file_name_all_completions")
(tramp-maybe-send-script
v tramp-shell-file-name-all-completions
"tramp_shell_file_name_all_completions"))
(dolist
(elt
(tramp-send-command-and-read
v (format
"%s %s"
(if (tramp-get-remote-perl v)
"tramp_perl_file_name_all_completions"
"tramp_shell_file_name_all_completions")
(tramp-shell-quote-argument localname))
'noerror)
result)
;; Don't cache "." and "..".
(when (string-match-p
directory-files-no-dot-files-regexp
(file-name-nondirectory (car elt)))
(tramp-set-file-property v (car elt) "file-exists-p" (nth 1 elt))
(tramp-set-file-property v (car elt) "file-readable-p" (nth 2 elt))
(tramp-set-file-property v (car elt) "file-directory-p" (nth 3 elt))
(tramp-set-file-property v (car elt) "file-executable-p" (nth 4 elt)))
(dolist
(elt
(tramp-send-command-and-read
v (format
"%s %s"
(if (tramp-get-remote-perl v)
"tramp_perl_file_name_all_completions"
"tramp_shell_file_name_all_completions")
(tramp-shell-quote-argument localname))
'noerror)
result)
;; Don't cache "." and "..".
(when (string-match-p
directory-files-no-dot-files-regexp
(file-name-nondirectory (car elt)))
(tramp-set-file-property v (car elt) "file-exists-p" (nth 1 elt))
(tramp-set-file-property v (car elt) "file-readable-p" (nth 2 elt))
(tramp-set-file-property v (car elt) "file-directory-p" (nth 3 elt))
(tramp-set-file-property v (car elt) "file-executable-p" (nth 4 elt)))
(push
(concat
(file-name-nondirectory (car elt)) (and (nth 3 elt) "/"))
result))))))))))
(push (file-name-nondirectory (car elt)) result))))))
;; cp, mv and ln
@ -2803,7 +2794,7 @@ The method used must be an out-of-band method."
(append switches (split-string (tramp-sh--quoting-style-options v))
(when dired `(,dired))))
(unless dired
(setq switches (delete "-N" (delete "--dired" switches)))))
(setq switches (seq-difference switches '("-N" "--dired")))))
(when wildcard
(setq wildcard (tramp-run-real-handler
#'file-name-nondirectory (list localname)))
@ -3917,11 +3908,13 @@ Fall back to normal file name handler if no Tramp handler exists."
(when rest-string
(tramp-message proc 10 "Previous string:\n%s" rest-string))
(tramp-message proc 6 "%S\n%s" proc string)
(setq string (concat rest-string string)
;; Fix action names.
string (string-replace "attributes changed" "attribute-changed" string)
string (string-replace "changes done" "changes-done-hint" string)
string (string-replace "renamed to" "moved" string))
(setq string
(thread-last
(concat rest-string string)
;; Fix action names.
(string-replace "attributes changed" "attribute-changed")
(string-replace "changes done" "changes-done-hint")
(string-replace "renamed to" "moved")))
(catch 'doesnt-work
;; https://bugs.launchpad.net/bugs/1742946
@ -5044,7 +5037,7 @@ Goes through the list `tramp-inline-compress-commands'."
;; Use plink options.
((string-match-p
(rx "plink" (? ".exe") eol)
(tramp-get-method-parameter vec 'tramp-login-program))
(tramp-expand-args vec 'tramp-login-program))
(concat
(if (eq tramp-use-connection-share 'suppress)
"-noshare" "-share")
@ -5405,7 +5398,7 @@ connection if a previous connection has died for some reason."
hop 'tramp-connection-timeout
tramp-connection-timeout))
(command
(tramp-get-method-parameter
(tramp-expand-args
hop 'tramp-login-program))
;; We don't create the temporary file. In
;; fact, it is just a prefix for the

View file

@ -603,12 +603,9 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(copy-directory filename newname keep-date 'parents 'copy-contents)
(tramp-barf-if-file-missing v filename
;; `file-local-copy' returns a file name also for a local
;; file with `jka-compr-handler', so we cannot trust its
;; result as indication for a remote file name.
(if-let* ((tmpfile
(and (tramp-tramp-file-p filename)
(file-local-copy filename))))
;; Suppress `jka-compr-handler'.
(if-let* ((jka-compr-inhibit t)
(tmpfile (file-local-copy filename)))
;; Remote filename.
(condition-case err
(rename-file tmpfile newname ok-if-already-exists)
@ -1068,18 +1065,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(defun tramp-smb-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for Tramp files."
(tramp-skeleton-file-name-all-completions filename directory
(all-completions
filename
(when (file-directory-p directory)
(with-parsed-tramp-file-name (expand-file-name directory) nil
(with-tramp-file-property v localname "file-name-all-completions"
(mapcar
(lambda (x)
(list
(if (string-search "d" (nth 1 x))
(file-name-as-directory (nth 0 x))
(nth 0 x))))
(tramp-smb-get-file-entries directory))))))))
(mapcar #'car (tramp-smb-get-file-entries directory))))
(defun tramp-smb-handle-file-system-info (filename)
"Like `file-system-info' for Tramp files."
@ -1752,9 +1738,6 @@ Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME YEAR)."
(unless share
(tramp-set-connection-property v "share-cache" res)))
;; Add directory itself.
(push '("" "drwxrwxrwx" 0 (0 0)) res)
;; Return entries.
(delq nil res)))))
@ -2295,9 +2278,6 @@ SHARE will be passed to the call of `tramp-smb-get-localname'."
;; * Return more comprehensive file permission string.
;;
;; * Try to remove the inclusion of dummy "" directory. Seems to be at
;; several places, especially in `tramp-smb-handle-insert-directory'.
;;
;; * Keep a separate connection process per share.
;;
;; * Keep a permanent connection process for `process-file'.

View file

@ -269,7 +269,7 @@ arguments to pass to the OPERATION."
(setq ret
(apply
#'tramp-call-process
v (tramp-get-method-parameter v 'tramp-login-program)
v (tramp-expand-args v 'tramp-login-program)
nil outbuf display
(tramp-expand-args
v 'tramp-login-args nil

View file

@ -498,24 +498,16 @@ the result will be a local, non-Tramp, file name."
(defun tramp-sudoedit-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for Tramp files."
(tramp-skeleton-file-name-all-completions filename directory
(all-completions
filename
(with-parsed-tramp-file-name (expand-file-name directory) nil
(with-tramp-file-property v localname "file-name-all-completions"
(tramp-sudoedit-send-command
v "ls" "-a1" "--quoting-style=literal" "--show-control-chars"
(if (tramp-string-empty-or-nil-p localname)
"" (file-name-unquote localname)))
(mapcar
(lambda (f)
(if (ignore-errors (file-directory-p (expand-file-name f directory)))
(file-name-as-directory f)
f))
(mapcar
(lambda (l) (and (not (string-match-p (rx bol (* blank) eol) l)) l))
(split-string
(tramp-get-buffer-string (tramp-get-connection-buffer v))
"\n" 'omit))))))))
(with-parsed-tramp-file-name (expand-file-name directory) nil
(tramp-sudoedit-send-command
v "ls" "-a1" "--quoting-style=literal" "--show-control-chars"
(if (tramp-string-empty-or-nil-p localname)
"" (file-name-unquote localname)))
(mapcar
(lambda (l) (and (not (string-match-p (rx bol (* blank) eol) l)) l))
(split-string
(tramp-get-buffer-string (tramp-get-connection-buffer v))
"\n" 'omit)))))
(defun tramp-sudoedit-handle-file-readable-p (filename)
"Like `file-readable-p' for Tramp files."

View file

@ -2002,12 +2002,11 @@ expected to be a string, which will be used."
"Construct a Tramp hop name from VEC."
(concat
(tramp-file-name-hop vec)
(replace-regexp-in-string
tramp-prefix-regexp ""
(replace-regexp-in-string
(rx (regexp tramp-postfix-host-regexp) eos)
tramp-postfix-hop-format
(tramp-make-tramp-file-name (tramp-file-name-unify vec))))))
(thread-last
(replace-regexp-in-string
(rx (regexp tramp-postfix-host-regexp) eos) tramp-postfix-hop-format
(tramp-make-tramp-file-name (tramp-file-name-unify vec)))
(replace-regexp-in-string tramp-prefix-regexp ""))))
(defun tramp-completion-make-tramp-file-name (method user host localname)
"Construct a Tramp file name from METHOD, USER, HOST and LOCALNAME.
@ -2957,7 +2956,7 @@ not in completion mode."
(or (and (cond
;; Completion styles like `flex' and `substring' check for
;; the file name "/". This does exist.
((string-equal filename "/"))
((string-equal filename tramp-prefix-format))
;; Is it a valid method?
((and (not (string-empty-p tramp-postfix-method-format))
(string-match
@ -3001,30 +3000,59 @@ not in completion mode."
(tramp-run-real-handler #'file-exists-p (list filename))))
(defvar tramp-fnac-add-trailing-slash t
"Whether `file-name-all-completions' shall add a trailing slash.
This is not desired, if that function is used in `directory-files', or
in `tramp-completion-handle-file-name-all-completions'.")
(defmacro tramp-skeleton-file-name-all-completions
(filename directory &rest body)
"Skeleton for `tramp-*-handle-filename-all-completions'.
BODY is the backend specific code."
(declare (indent 2) (debug t))
`(ignore-error file-missing
(seq-uniq (delq nil (delete ""
(let* ((case-fold-search read-file-name-completion-ignore-case)
(result (progn ,@body)))
;; Some storage systems do not return "." and "..".
(when (tramp-tramp-file-p ,directory)
(dolist (elt '(".." "."))
(when (string-prefix-p ,filename elt)
(setq result (cons (concat elt "/") result)))))
(if (consp completion-regexp-list)
;; Discriminate over `completion-regexp-list'.
(mapcar
(lambda (x)
(when (stringp x)
(catch 'match
(dolist (elt completion-regexp-list x)
(unless (string-match-p elt x) (throw 'match nil))))))
result)
result)))))))
(all-completions
,filename
(when (file-directory-p ,directory)
(seq-uniq (delq nil
(let* ((case-fold-search read-file-name-completion-ignore-case)
(result
(if (tramp-tramp-file-p ,directory)
(with-parsed-tramp-file-name
(expand-file-name ,directory) nil
(when (and (not (string-search "/" ,filename))
(tramp-connectable-p v))
(with-tramp-file-property
v localname
(format
"file-name-all-completions-%s"
tramp-fnac-add-trailing-slash)
;; Mark symlinked directories. Other
;; directories are already marked.
(mapcar
(lambda (x)
(let ((f (file-name-concat ,directory x)))
(if (and tramp-fnac-add-trailing-slash
(not (string-suffix-p "/" x))
(file-directory-p
(if (file-symlink-p f)
(file-truename f) f)))
(concat x "/") x)))
;; Some storage systems do not return "." and "..".
(seq-union
(seq-difference (progn ,@body) '("." ".."))
'("./" "../"))))))
,@body)))
;; Discriminate over `completion-regexp-list'.
(if (consp completion-regexp-list)
(mapcar
(lambda (x)
(when (stringp x)
(catch 'match
(dolist (elt completion-regexp-list x)
(unless (string-match-p elt x) (throw 'match nil))))))
result)
result))))))))
(defvar tramp--last-hop-directory nil
"Tracks the directory from which to run login programs.")
@ -3035,72 +3063,74 @@ BODY is the backend specific code."
;; completions.
(defun tramp-completion-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for partial Tramp files."
(tramp-skeleton-file-name-all-completions filename directory
(let ((fullname
(tramp-drop-volume-letter (expand-file-name filename directory)))
(directory (tramp-drop-volume-letter directory))
tramp--last-hop-directory hop result result1)
(let (tramp-fnac-add-trailing-slash)
(tramp-skeleton-file-name-all-completions filename directory
(let ((fullname
(tramp-drop-volume-letter (expand-file-name filename directory)))
(directory (tramp-drop-volume-letter directory))
tramp--last-hop-directory hop result result1)
;; Suppress hop from completion.
(when (string-match
(rx
(regexp tramp-prefix-regexp)
(group (+ (regexp tramp-remote-file-name-spec-regexp)
(regexp tramp-postfix-hop-regexp))))
fullname)
(setq hop (match-string 1 fullname)
fullname (replace-match "" nil nil fullname 1)
tramp--last-hop-directory
(tramp-make-tramp-file-name (tramp-dissect-hop-name hop))))
;; Suppress hop from completion.
(when (string-match
(rx
(regexp tramp-prefix-regexp)
(group (+ (regexp tramp-remote-file-name-spec-regexp)
(regexp tramp-postfix-hop-regexp))))
fullname)
(setq hop (match-string 1 fullname)
fullname (replace-match "" nil nil fullname 1)
tramp--last-hop-directory
(tramp-make-tramp-file-name (tramp-dissect-hop-name hop))))
(let (tramp-default-user tramp-default-user-alist
tramp-default-host tramp-default-host-alist)
(let (tramp-default-user tramp-default-user-alist
tramp-default-host tramp-default-host-alist)
;; Possible completion structures.
(dolist (elt (tramp-completion-dissect-file-name fullname))
(let* ((method (tramp-file-name-method elt))
(user (tramp-file-name-user elt))
(host (tramp-file-name-host elt))
(localname (tramp-file-name-localname elt))
(m (tramp-find-method method user host))
all-user-hosts)
;; Possible completion structures.
(dolist (elt (tramp-completion-dissect-file-name fullname))
(let* ((method (tramp-file-name-method elt))
(user (tramp-file-name-user elt))
(host (tramp-file-name-host elt))
(localname (tramp-file-name-localname elt))
(m (tramp-find-method method user host))
all-user-hosts)
(unless localname ;; Nothing to complete.
(if (or user host)
;; Method dependent user / host combinations.
(progn
(mapc
(lambda (x)
(setq all-user-hosts
(append all-user-hosts
(funcall (nth 0 x) (nth 1 x)))))
(tramp-get-completion-function m))
(unless localname ;; Nothing to complete.
(if (or user host)
;; Method dependent user / host combinations.
(progn
(mapc
(lambda (x)
(setq all-user-hosts
(append all-user-hosts
(funcall (nth 0 x) (nth 1 x)))))
(tramp-get-completion-function m))
(setq result
(append result
(mapcar
(lambda (x)
(tramp-get-completion-user-host
method user host (nth 0 x) (nth 1 x)))
all-user-hosts))))
(setq result
(append result
(mapcar
(lambda (x)
(tramp-get-completion-user-host
method user host (nth 0 x) (nth 1 x)))
all-user-hosts))))
;; Possible methods.
(setq result
(append result (tramp-get-completion-methods m hop)))))))
;; Possible methods.
(setq result
(append result (tramp-get-completion-methods m hop)))))))
;; Add hop.
(dolist (elt result)
(when elt
(setq elt (replace-regexp-in-string
tramp-prefix-regexp (concat tramp-prefix-format hop) elt))
(push (substring elt (length directory)) result1)))
;; Add hop.
(dolist (elt result)
(when elt
(setq elt (replace-regexp-in-string
tramp-prefix-regexp
(concat tramp-prefix-format hop) elt))
(push (substring elt (length directory)) result1)))
;; Complete local parts.
(append
result1
(ignore-errors
(tramp-run-real-handler
#'file-name-all-completions (list filename directory))))))))
;; Complete local parts.
(append
result1
(ignore-errors
(tramp-run-real-handler
#'file-name-all-completions (list filename directory)))))))))
;; Method, host name and user name completion for a file.
(defun tramp-completion-handle-file-name-completion
@ -3659,9 +3689,10 @@ BODY is the backend specific code."
(signal 'error nil)
(setf ,directory
(file-name-as-directory (expand-file-name ,directory)))
(let ((temp
(with-tramp-file-property v localname "directory-files" ,@body))
result item)
(let* (tramp-fnac-add-trailing-slash
(temp
(with-tramp-file-property v localname "directory-files" ,@body))
result item)
(while temp
(setq item (directory-file-name (pop temp)))
(when (or (null ,match) (string-match-p ,match item))
@ -4496,8 +4527,8 @@ Let-bind it when necessary.")
;; "." and ".." are never interesting as completions, and are
;; actually in the way in a directory with only one file. See
;; file_name_completion() in dired.c.
(when (and (consp fnac) (length= (delete "./" (delete "../" fnac)) 1))
(setq fnac (delete "./" (delete "../" fnac))))
(when (and (consp fnac) (length= (seq-difference fnac '("./" "../")) 1))
(setq fnac (seq-difference fnac '("./" "../"))))
(or
(try-completion
filename fnac
@ -5294,7 +5325,7 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.")
(defvar tramp-extra-expand-args nil
"Method specific arguments.")
(defun tramp-expand-args (vec parameter default &rest spec-list)
(defun tramp-expand-args (vec parameter &optional default &rest spec-list)
"Expand login arguments as given by PARAMETER in `tramp-methods'.
PARAMETER is a symbol like `tramp-login-args', denoting a list of
list of strings from `tramp-methods', containing %-sequences for
@ -5317,12 +5348,15 @@ a connection-local variable."
(setq spec-list (cddr spec-list)))
(setq spec (apply #'format-spec-make extra-spec-list))
;; Expand format spec.
(flatten-tree
(mapcar
(lambda (x)
(setq x (mapcar (lambda (y) (tramp-format-spec y spec)) x))
(unless (member "" x) x))
args))))
(cond
((consp args)
(flatten-tree
(mapcar
(lambda (x)
(setq x (mapcar (lambda (y) (tramp-format-spec y spec)) x))
(unless (member "" x) x))
args)))
(args (tramp-format-spec args spec)))))
(defun tramp-post-process-creation (proc vec)
"Apply actions after creation of process PROC."
@ -5444,8 +5478,7 @@ processes."
(tramp-get-method-parameter v 'tramp-direct-async)
`(,(string-join command " ")))
command))
(login-program
(tramp-get-method-parameter v 'tramp-login-program))
(login-program (tramp-expand-args v 'tramp-login-program))
;; We don't create the temporary file. In fact, it is just
;; a prefix for the ControlPath option of ssh; the real
;; temporary file has another name, and it is created and
@ -5487,7 +5520,7 @@ processes."
v 'tramp-login-args nil
?h (or host "") ?u (or user "") ?p (or port "")
?c (format-spec (or options "") (format-spec-make ?t tmpfile))
?d (or device "") ?a (or pta "") ?l ""))))
?w "" ?d (or device "") ?a (or pta "") ?l ""))))
;; Suppress `internal-default-process-sentinel', which is set
;; when :sentinel is nil. (Bug#71049)
p (make-process

View file

@ -129,6 +129,7 @@ Linum mode is a buffer-local minor mode."
;; Note that nowadays, this actually doesn't show line
;; numbers in client frames at all, because we visit the
;; file before creating the client frame. See bug#35726.
;; Use `frame-initial-p'?
(and (daemonp) (eq (selected-frame) terminal-frame)))
(linum-mode 1)))

View file

@ -326,10 +326,10 @@ non-nil and point is located on the heading line.")
(defcustom outline-minor-mode-use-buttons nil
"Whether to display clickable buttons on the headings.
These buttons can be used to hide and show the body under the heading.
When the value is `insert', additional placeholders for buttons are
When the value is \\+`insert', additional placeholders for buttons are
inserted to the buffer, so buttons are not only clickable,
but also typing `RET' on them can hide and show the body.
Using the value `insert' is not recommended in editable
Using the value \\+`insert' is not recommended in editable
buffers because it modifies them.
When the value is `in-margins', then clickable buttons are
displayed in the margins before the headings.
@ -513,7 +513,7 @@ font-lock faces defined by the major mode. Thus, a non-nil value will
work well only when there's no such conflict.
If the value is t, use outline faces only if there are no major mode's
font-lock faces on headings. When `override', completely overwrite major
mode's font-lock faces with outline faces. When `append', try to append
mode's font-lock faces with outline faces. When \\+`append', try to append
outline font-lock faces to those of major mode."
:type '(choice (const :tag "Do not use outline font-lock highlighting" nil)
(const :tag "Overwrite major mode font-lock faces" override)

View file

@ -434,9 +434,10 @@ It is the default value of `show-paren-data-function'."
(overlay-put show-paren--context-overlay 'priority
show-paren-priority)
(overlay-put show-paren--context-overlay
'face `(:box
( :line-width (1 . -1)
:color ,(face-attribute 'shadow :foreground))))
'face `( :inherit default
:box
( :line-width (1 . -1)
:color ,(face-attribute 'shadow :foreground))))
(add-hook 'post-command-hook #'show-paren--delete-context-overlay
nil 'local))

View file

@ -1431,7 +1431,7 @@ COMMAND Name of the program for printing a text file. On MS-DOS and
specially, using NAME as the destination for output; any other
program is treated like `lpr' except that an explicit filename
is given as the last argument.
If COMMAND is nil, it's used the default printing program:
If COMMAND is nil, it stands for the default printing program:
`print' for Windows system, `lp' for lp system and `lpr' for
all other systems. See also `pr-path-alist'.
Examples:
@ -1506,7 +1506,10 @@ Useful links:
:type '(repeat
(list :tag "Text Printer"
(symbol :tag "Printer Symbol Name")
(string :tag "Printer Command")
(choice :menu-tag "Printer Command"
:tag "Printer Command"
(const :tag "Default print command" nil)
(string :tag "Explicit print command"))
(repeat :tag "Printer Switches"
(sexp :tag "Switch" :value ""))
(choice :menu-tag "Printer Name"
@ -1577,7 +1580,7 @@ COMMAND Name of the program for printing a PostScript file. On MS-DOS
specially, using NAME as the destination for output; any other
program is treated like `lpr' except that an explicit filename
is given as the last argument.
If COMMAND is nil, it's used the default printing program:
If COMMAND is nil, it stands for the default printing program:
`print' for Windows system, `lp' for lp system and `lpr' for
all other systems. See also `pr-path-alist'.
Examples:
@ -1756,7 +1759,10 @@ Useful links:
(list
:tag "PostScript Printer"
(symbol :tag "Printer Symbol Name")
(string :tag "Printer Command")
(choice :menu-tag "Printer Command"
:tag "Printer Command"
(const :tag "Default print command" nil)
(string :tag "Explicit print command"))
(repeat :tag "Printer Switches"
(sexp :tag "Switch" :value ""))
(choice :menu-tag "Printer Name Switch"

View file

@ -1567,6 +1567,7 @@ recommended to enable `electric-pair-mode' with this mode."
(funcall c-ts-mode-indent-style)
(c-ts-mode--simple-indent-rules
'cpp c-ts-mode-indent-style)))
(setq-local editorconfig-indent-size-vars '(c-ts-indent-offset))
;; Font-lock.
(setq-local treesit-font-lock-settings

View file

@ -991,6 +991,8 @@ You might also use mode hooks to specify it in certain modes, like this:
(file-name-sans-extension buffer-file-name))))))))
It's often useful to leave a space at the end of the value."
:group 'compilation
:initialize #'custom-initialize-delay
:type 'string)
;;;###autoload(put 'compile-command 'safe-local-variable (lambda (a) (and (stringp a) (if (boundp 'compilation-read-command) compilation-read-command t))))

View file

@ -2,12 +2,12 @@
;; Copyright (C) 2018-2026 Free Software Foundation, Inc.
;; Version: 1.21
;; Version: 1.23
;; Author: João Távora <joaotavora@gmail.com>
;; Maintainer: João Távora <joaotavora@gmail.com>
;; URL: https://github.com/joaotavora/eglot
;; Keywords: convenience, languages
;; Package-Requires: ((emacs "26.3") (eldoc "1.14.0") (external-completion "0.1") (flymake "1.4.2") (jsonrpc "1.0.26") (project "0.11.2") (seq "2.23") (xref "1.6.2"))
;; Package-Requires: ((emacs "26.3") (eldoc "1.16.0") (external-completion "0.1") (flymake "1.4.5") (jsonrpc "1.0.28") (project "0.11.2") (seq "2.23") (xref "1.7.0"))
;; This is a GNU ELPA :core package. Avoid adding functionality
;; that is not available in the version of Emacs recorded above or any
@ -2710,10 +2710,11 @@ still unanswered LSP requests to the server\n"))))
(defconst eglot-mode-line-progress
'(:eval
(when-let ((server (eglot-current-server)))
(when-let ((s (eglot-current-server)))
(cl-loop
for pr hash-values of (eglot--progress-reporters server)
when (eq (car pr) 'eglot--mode-line-reporter)
for pr in (cl-delete 'eglot--mode-line-reporter
(hash-table-values (eglot--progress-reporters s))
:key #'car :test-not #'eq)
for v = (nth 4 pr)
when v sum 1 into n and sum v into acc
collect (format "(%s) %s %s" (nth 1 pr) (nth 2 pr) (nth 3 pr))
@ -4092,7 +4093,7 @@ for which LSP on-type-formatting should be requested."
parameter
;; ...perhaps highlight it in the formals list
(when (eq i active-param)
(save-excursion ;; FIXME: Sink into the `if' or hoist out of loop?
(save-excursion
(goto-char (point-min))
(pcase-let
((`(,beg ,end)
@ -4100,8 +4101,7 @@ for which LSP on-type-formatting should be requested."
(let ((case-fold-search nil))
(and (search-forward parlabel (line-end-position) t)
(list (match-beginning 0) (match-end 0))))
(list (+ (point-min) (aref parlabel 0))
(+ (point-min) (aref parlabel 1))))))
(list (1+ (aref parlabel 0)) (1+ (aref parlabel 1))))))
(if (and beg end)
(add-face-text-property
beg end

View file

@ -1330,6 +1330,8 @@ Interactively, with a prefix arg, FORCE is t."
(buffer (current-buffer)))
(cl-labels
((visible-buffer-window ()
;; This can use `frame-initial-p' once
;; we can assume Emacs 31 or later.
(and (or (not (daemonp))
(not (eq (selected-frame) terminal-frame)))
(get-buffer-window (current-buffer))))

View file

@ -1089,11 +1089,15 @@ list is empty)."
match)
(while (setq match (text-property-search-forward 'compilation-annotation))
(add-text-properties (prop-match-beginning match) (prop-match-end match)
'(read-only t)))
'(read-only t front-sticky t)))
(goto-char (point-min))
(while (setq match (text-property-search-forward 'compilation-message))
(add-text-properties (prop-match-beginning match) (prop-match-end match)
'(read-only t occur-prefix t))
'( read-only t occur-prefix t
;; Allow insertion of text right
;; after prefix, but not before.
front-sticky t
rear-nonsticky t))
(let ((loc (compilation--message->loc (prop-match-value match)))
m)
;; Update the markers if necessary.

View file

@ -73,6 +73,7 @@
(require 'cl-lib)
(require 'ring)
(require 'project)
(require 'text-property-search)
(eval-and-compile
(when (version< emacs-version "28.0.60")
@ -628,7 +629,7 @@ If SELECT is non-nil, select the target window."
(run-hooks 'xref-after-jump-hook)))
;;; XREF buffer (part of the UI)
;;; Xref buffer (part of the UI)
;; The xref buffer is used to display a set of xrefs.
(defconst xref-buffer-name "*xref*"
@ -1004,12 +1005,13 @@ point."
(define-key map (kbd ".") #'xref-next-line)
(define-key map (kbd ",") #'xref-prev-line)
(define-key map (kbd "M-,") #'xref-quit-and-pop-marker-stack)
(define-key map (kbd "e") #'xref-change-to-xref-edit-mode)
map))
(declare-function outline-search-text-property "outline"
(property &optional value bound move backward looking-at))
(define-derived-mode xref--xref-buffer-mode special-mode "XREF"
(define-derived-mode xref--xref-buffer-mode special-mode "Xref"
"Mode for displaying cross-references."
(setq buffer-read-only t)
(setq next-error-function #'xref--next-error-function)
@ -1039,7 +1041,7 @@ point."
(define-derived-mode xref--transient-buffer-mode
xref--xref-buffer-mode
"XREF Transient.")
"Xref Transient")
(defun xref--imenu-prev-index-position ()
"Move point to previous line in `xref' buffer.
@ -1470,6 +1472,106 @@ between them by typing in the minibuffer with completion."
(define-obsolete-function-alias
'xref--show-defs-minibuffer #'xref-show-definitions-completing-read "28.1")
(defun xref-edit--prepare-buffer ()
"Mark relevant regions read-only, and add relevant occur text-properties."
(save-excursion
(goto-char (point-min))
(let ((inhibit-read-only t)
match)
(while (setq match (text-property-search-forward 'xref-group))
(add-text-properties (prop-match-beginning match) (prop-match-end match)
'( read-only t
front-sticky t)))
(goto-char (point-min))
(while (setq match (text-property-search-forward 'xref-item))
(let ((line-number-end (save-excursion
(forward-line 0)
(and (looking-at " *[0-9]+:")
(match-end 0)))))
(when line-number-end
(add-text-properties (prop-match-beginning match) line-number-end
'( read-only t
occur-prefix t
;; Allow insertion of text right
;; after prefix, but not before.
front-sticky t
rear-nonsticky t))))))))
(defvar xref-edit-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-c") #'xref-edit-save-changes)
(define-key map (kbd "RET") #'xref-goto-xref)
(define-key map (kbd "M-,") #'xref-quit-and-pop-marker-stack)
(define-key map (kbd "C-o") #'xref-show-location-at-point)
map)
"Keymap for `xref-edit-mode'.")
(defvar xref-edit-mode-hook nil
"Hooks run when changing to Xref-Edit mode.")
(defun xref-edit-mode ()
"Major mode for editing *xref* buffers.
In this mode, changes to the *xref* buffer are applied to the
originating files.
\\<xref-edit-mode-map>
Type \\[xref-edit-save-changes] to exit Xref-Edit mode, return to Xref
mode.
The only editable texts in an Xref-Edit buffer are the match results."
(interactive)
(error "This mode can be enabled only by `xref-change-to-xref-edit-mode'"))
(put 'xref-edit-mode 'mode-class 'special)
(defun xref-change-to-xref-edit-mode ()
"Switch to `xref-edit-mode' to edit *xref* buffer."
(interactive)
(unless (derived-mode-p 'xref--xref-buffer-mode)
(error "Not an Xref buffer"))
(use-local-map xref-edit-mode-map)
(xref-edit--prepare-buffer)
(setq buffer-read-only nil)
(setq major-mode 'xref-edit-mode)
(setq mode-name "Xref-Edit")
(buffer-enable-undo)
(set-buffer-modified-p nil)
(setq buffer-undo-list nil)
(add-hook 'before-change-functions #'xref-edit--before-change-function nil t)
(add-hook 'after-change-functions #'occur-after-change-function nil t)
(run-mode-hooks 'xref-edit-mode-hook)
(message (substitute-command-keys
"Editing: Type \\[xref-edit-save-changes] to return to Xref mode")))
(defun xref-edit-save-changes ()
"Switch back to Xref mode."
(interactive)
(unless (derived-mode-p 'xref-edit-mode)
(error "Not a Xref-Edit buffer"))
(remove-hook 'before-change-functions #'xref-edit--before-change-function t)
(remove-hook 'after-change-functions #'occur-after-change-function t)
(use-local-map xref--xref-buffer-mode-map)
(setq buffer-read-only t)
(setq major-mode 'xref--xref-buffer-mode)
(setq mode-name "Xref")
(force-mode-line-update)
(buffer-disable-undo)
(setq buffer-undo-list t)
(let ((inhibit-read-only t))
(remove-text-properties (point-min) (point-max)
'(occur-target nil occur-prefix nil)))
(message "Switching to Xref mode"))
(defun xref-edit--before-change-function (_beg _end)
(when (and (not (get-text-property (pos-bol) 'occur-target))
(get-text-property (pos-bol) 'occur-prefix))
(let ((m (xref-location-marker (xref-item-location
(get-text-property (pos-bol) 'xref-item))))
(inhibit-read-only t)
(inhibit-modification-hooks t)
(buffer-undo-list t))
(add-text-properties (pos-bol) (pos-eol)
`(occur-target ((,m . ,m)))))))
(defcustom xref-show-xrefs-function 'xref--show-xref-buffer
"Function to display a list of search results.

View file

@ -706,6 +706,7 @@ the `server-process' variable."
;; when we can't get user input, which may happen when
;; doing emacsclient --eval "(kill-emacs)" in daemon mode.
(cond
;; Use `frame-initial-p'?
((and (daemonp)
(null (cdr (frame-list)))
(eq (selected-frame) terminal-frame))
@ -1429,6 +1430,7 @@ The following commands are accepted by the client:
(or (eq use-current-frame 'always)
;; We can't use the Emacs daemon's
;; terminal frame.
;; Use `frame-initial-p'?
(not (and (daemonp)
(null (cdr (frame-list)))
(eq (selected-frame)
@ -1453,6 +1455,7 @@ The following commands are accepted by the client:
;; If there won't be a current frame to use, fall
;; back to trying to create a new one.
((and use-current-frame
;; Use `frame-initial-p'?
(daemonp)
(null (cdr (frame-list)))
(eq (selected-frame) terminal-frame)

View file

@ -160,6 +160,10 @@ of previous VARs.
(push `(set-default ',(pop args) ,(pop args)) exps))
`(progn . ,(nreverse exps))))
(defun set-local (variable value)
"Make VARIABLE buffer local and set it to VALUE."
(set (make-local-variable variable) value))
(defmacro setq-local (&rest pairs)
"Make each VARIABLE local to current buffer and set it to corresponding VALUE.
@ -181,7 +185,7 @@ In some corner cases you may need to resort to
\(fn [VARIABLE VALUE]...)"
(declare (debug setq))
(unless (evenp (length pairs))
(error "PAIRS must have an even number of variable/value members"))
(signal 'wrong-number-of-arguments (list 'setq-local (length pairs))))
(let ((expr nil))
(while pairs
(unless (symbolp (car pairs))
@ -229,7 +233,7 @@ in order to restore the state of the local variables set via this macro.
\(fn [VARIABLE VALUE]...)"
(declare (debug setq))
(unless (evenp (length pairs))
(error "PAIRS must have an even number of variable/value members"))
(signal 'wrong-number-of-arguments (list 'buffer-local-set-state (length pairs))))
(let ((vars nil)
(tmp pairs))
(while tmp (push (car tmp) vars) (setq tmp (cddr tmp)))
@ -1226,8 +1230,13 @@ with
(member-if (lambda (x) (foo (bar x))) items)"
(declare (compiler-macro
(lambda (_)
(let ((x (make-symbol "x")))
`(drop-while (lambda (,x) (not (funcall ,pred ,x))) ,list)))))
(let* ((x (make-symbol "x"))
(f (and (not (internal--effect-free-fun-arg-p pred))
(make-symbol "f")))
(form `(drop-while (lambda (,x)
(not (funcall ,(or f pred) ,x)))
,list)))
(if f `(let ((,f ,pred)) ,form) form)))))
(drop-while (lambda (x) (not (funcall pred x))) list))
;; This is good to have for improved readability in certain uses, but

View file

@ -292,6 +292,7 @@ a list of frames to update."
(and (eq auto-resize-tab-bars 'grow-only)
(> (frame-parameter frame 'tab-bar-lines) 1))
;; Don't enable tab-bar in daemon's initial frame.
;; Use `frame-initial-p'?
(and (daemonp) (eq frame terminal-frame)))
(set-frame-parameter frame 'tab-bar-lines
(tab-bar--tab-bar-lines-for-frame frame)))))

View file

@ -3,7 +3,7 @@
;; Copyright (C) 2006-2026 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Maintainer: Simen Heggestøyl <simenheg@gmail.com>
;; Maintainer: Simen Heggestøyl <simenheg@runbox.com>
;; Keywords: hypermedia
;; This file is part of GNU Emacs.
@ -66,7 +66,7 @@
(defconst css-pseudo-class-ids
'("active" "checked" "default" "disabled" "empty" "enabled" "first"
"first-child" "first-of-type" "focus" "focus-within" "hover"
"first-child" "first-of-type" "focus" "focus-within" "has" "hover"
"in-range" "indeterminate" "invalid" "lang" "last-child"
"last-of-type" "left" "link" "not" "nth-child" "nth-last-child"
"nth-last-of-type" "nth-of-type" "only-child" "only-of-type"

View file

@ -390,6 +390,16 @@ which can be the value of the `face' text property."
(list (list "x-color" (cadr face))))
((and (listp face) (eq (car face) :background))
(list (list "x-bg-color" (cadr face))))
((and (listp face) (eq (car face) :underline))
(list (list "underline")))
((and (listp face)
(eq (car face) :weight)
(eq (cadr face) 'bold))
(list (list "bold")))
((and (listp face)
(eq (car face) :slant)
(memq (cadr face) '(italic oblique)))
(list (list "italic")))
((listp face)
(apply #'append (mapcar #'enriched-face-ans face)))
((let* ((fg (face-attribute face :foreground))

View file

@ -1700,7 +1700,7 @@ and URL `https://rhodesmill.org/brandon/2012/one-sentence-per-line/'."
(to (copy-marker (max from to) t))
pfx)
(goto-char from)
(let ((fill-column (* 2 (point-max)))) ; Wide characters span up to two columns.
(let ((fill-column most-positive-fixnum))
(setq pfx (or (save-excursion
(fill-region-as-paragraph-default (point)
to

View file

@ -40,6 +40,7 @@
(require 'treesit)
(require 'subr-x)
(require 'outline)
(require 'seq)
(treesit-declare-unavailable-functions)
@ -296,7 +297,12 @@ the same features enabled in MODE."
(plist-get configs :simple-indent)))
(setq treesit-range-settings
(append treesit-range-settings
(plist-get configs :range)))
;; Filter out function queries, because they are
;; usually some hack and might escape the code block.
;; Case in point: c-ts-mode's range setting.
(seq-filter (lambda (setting)
(not (functionp (car setting))))
(plist-get configs :range))))
(setq-local indent-line-function #'treesit-indent)
(setq-local indent-region-function #'treesit-indent-region)))

View file

@ -53,7 +53,7 @@ with %, which are converted as follows:
%H 24-hour clock hour %I 12-hour clock hour
%m month number
%M minute
%p meridian indicator: `AM', `PM'
%p meridiem indicator: `AM', `PM'
%S seconds
%w day number of week, Sunday is 0
%Y 4-digit year %y 2-digit year
@ -1039,39 +1039,45 @@ This is an internal function called by `time-stamp'."
offset-secs)
"Format a time offset according to a %z variation.
With no flags, the output includes hours and minutes: +-HHMM
unless there is a non-zero seconds part, in which case the seconds
are included: +-HHMMSS
FLAG-MINIMIZE is whether \"-\" was specified. If non-nil, the
output may be limited to hours if minutes and seconds are zero.
FLAG-PAD-SPACES-ONLY is whether \"_\" was specified. If non-nil,
seconds must be output, so that any padding can be spaces only.
FLAG-PAD-ZEROS-FIRST is whether \"0\" was specified. If non-nil,
padding to the requested FIELD-WIDTH (if any) is done by adding
00 seconds before padding with spaces.
COLON-COUNT is the number of colons preceding the \"z\" (0-3). One or
two colons put that many colons in the output (+-HH:MM or +-HH:MM:SS).
Three colons outputs only hours if minutes and seconds are zero and
includes colon separators if minutes and seconds are output.
FIELD-WIDTH is a whole number giving the minimum number of characters
in the output; 0 specifies no minimum. Additional characters will be
added on the right if necessary. The added characters will be spaces
unless FLAG-PAD-ZEROS-FIRST is non-nil.
OFFSET-SECS is the time zone offset (in seconds east of UTC) to be
formatted according to the preceding parameters.
Format parts FLAG-MINIMIZE, FLAG-PAD-SPACES-ONLY,
FLAG-PAD-ZEROS-FIRST, COLON-COUNT, and FIELD-WIDTH
are used to format time zone offset OFFSET-SECS.
This is an internal function used by `time-stamp'."
;; Callers of this function need to have already parsed the %z
;; format string; this function accepts just the parts of the format.
;; `time-stamp-string-preprocess' is the full-fledged parser normally
;; used. The unit test (in time-stamp-tests.el) defines the simpler
;; parser `format-time-offset'.
;; OFFSET-SECS is the time zone offset (in seconds east of UTC) to be
;; formatted according to the following parameters.
;; FLAG-MINIMIZE is whether \"-\" was specified. If non-nil, the
;; output may be limited to hours if minutes and seconds are zero.
;; FLAG-PAD-SPACES-ONLY is whether \"_\" was specified. If non-nil,
;; seconds must be output, so that any padding can be spaces only.
;; FLAG-PAD-ZEROS-FIRST is whether \"0\" was specified. If non-nil,
;; padding to the requested FIELD-WIDTH (if any) is done by adding
;; 00 seconds before padding with spaces.
;; COLON-COUNT is the number of colons preceding the \"z\" (0-3). One or
;; two colons put that many colons in the output (+-HH:MM or +-HH:MM:SS).
;; Three colons outputs only hours if minutes and seconds are zero and
;; includes colon separators if minutes and seconds are output.
;; FIELD-WIDTH is a whole number giving the minimum number of characters
;; in the output; 0 specifies no minimum. Additional characters will be
;; added on the right if necessary. The added characters will be spaces
;; unless FLAG-PAD-ZEROS-FIRST is non-nil.
;; With no flags set, the output includes hours and minutes: +-HHMM
;; unless there is a non-zero seconds part, in which case the seconds
;; are included: +-HHMMSS
(let ((hrs (/ (abs offset-secs) 3600))
(mins (/ (% (abs offset-secs) 3600) 60))
(secs (% (abs offset-secs) 60))

View file

@ -330,7 +330,7 @@ holds a keymap."
:vert-only t)
(tool-bar-add-item-from-menu 'menu-find-file-existing "open" nil
:label "Open" :vert-only t)
(tool-bar-add-item-from-menu 'dired "diropen" nil :vert-only t)
(tool-bar-add-item-from-menu 'dired-from-menubar "diropen" nil :vert-only t)
(tool-bar-add-item-from-menu 'kill-this-buffer "close" nil :vert-only t)
(tool-bar-add-item-from-menu 'save-buffer "save" nil
:label "Save")

View file

@ -753,10 +753,10 @@ that encompasses the region between START and END."
(numberp (cdr range-offset)))
(signal 'treesit-error (list "Value of :offset option should be a pair of numbers" range-offset)))
(setq offset range-offset)))
(:range-fn (let ((range-fn (pop query-specs)))
(unless (functionp range-fn)
(signal 'treesit-error (list "Value of :range-fn option should be a function" range-fn)))
(setq range-fn range-fn)))
(:range-fn (let ((fn (pop query-specs)))
(unless (functionp fn)
(signal 'treesit-error (list "Value of :range-fn option should be a function" fn)))
(setq range-fn fn)))
(query (if (functionp query)
(push (list query nil nil) result)
(when (null embed)
@ -1423,22 +1423,31 @@ LANGUAGE is the language of QUERY.")
(setf (nth 1 new-setting) t)
new-setting))
(defun treesit--font-lock-level-setter (sym val)
(defun treesit--font-lock-level-setter (sym val &optional buffer-local)
"Custom setter for `treesit-font-lock-level'.
Set the default value of SYM to VAL, recompute fontification
features and refontify for every buffer where tree-sitter-based
fontification is enabled."
(set-default sym val)
(when (treesit-available-p)
(dolist (buffer (buffer-list))
(with-current-buffer buffer
;; FIXME: This doesn't re-run major mode hooks, meaning any
;; customization done in major mode hooks (e.g., with
;; `treesit-font-lock-recompute-features') is lost.
(when treesit-font-lock-settings
(treesit-font-lock-recompute-features)
(treesit-font-lock-fontify-region
(point-min) (point-max)))))))
fontification is enabled.
If optional BUFFER-LOCAL is non-nil, only affect the current buffer.
Set SYM buffer locally and refontify."
;; FIXME: This doesn't re-run major mode hooks, meaning any
;; customization done in major mode hooks (e.g., with
;; `treesit-font-lock-recompute-features') may be overridden.
(cond (buffer-local
(set-local sym val)
(when (and (treesit-available-p)
treesit-font-lock-settings)
(treesit-font-lock-recompute-features)
(font-lock-flush)))
(t
(set-default sym val)
(when (treesit-available-p)
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(when treesit-font-lock-settings
(treesit-font-lock-recompute-features)
(font-lock-flush))))))))
(defcustom treesit-font-lock-level 3
"Decoration level to be used by tree-sitter fontifications.
@ -2050,9 +2059,8 @@ If LOUDLY is non-nil, display some debugging information."
(pcase-let ((`(,max-depth ,max-width)
(treesit-subtree-stat
(treesit-buffer-root-node language))))
(if (or (> max-depth 100) (> max-width 4000))
(setq treesit--font-lock-fast-mode t)
(setq treesit--font-lock-fast-mode nil))))
(setq treesit--font-lock-fast-mode
(or (> max-depth 100) (> max-width 4000)))))
;; Only activate if ENABLE flag is t.
(when-let*
@ -5849,7 +5857,7 @@ language."
"Pattern matching"
(treesit-query-capture
:no-eval (treesit-query-capture node '((identifier) @id "return" @ret))
:eg-result-string "((id . #<treesit-node (identifier) in 195-196>) (ret . #<treesit-node "return" in 338-344>))")
:eg-result-string "((id . #<treesit-node (identifier) in 195-196>) (ret . #<treesit-node \"return\" in 338-344>))")
(treesit-query-compile
:no-eval (treesit-query-compile 'c '((identifier) @id "return" @ret))
:eg-result-string "#<treesit-compiled-query>")

View file

@ -977,6 +977,7 @@ In the latter case, VC mode is deactivated for this buffer."
noninteractive
;; Copied from server-start. Seems like there should
;; be a better way to ask "can we get user input?"...
;; Use `frame-initial-p'?
(and (daemonp)
(null (cdr (frame-list)))
(eq (selected-frame) terminal-frame))

View file

@ -907,9 +907,9 @@ means that `whitespace-mode' is turned on for buffers in C and
C++ modes only.
Global `whitespace-mode' will not automatically turn on in internal
buffers (with name starting from space) and special buffers (with name
starting from \"*\"), except \"*scratch*\" buffer. Use
`whitespace-global-mode-buffers' to customize this behavior."
buffers (whose names start with a space) and special buffers (whose
names start with \"*\"), with the exception of the \"*scratch*\" buffer.
Use `whitespace-global-mode-buffers' to customize this behavior."
:type '(choice :tag "Global Modes"
(const :tag "None" nil)
(const :tag "All" t)
@ -919,11 +919,11 @@ starting from \"*\"), except \"*scratch*\" buffer. Use
(repeat :inline t
(symbol :tag "Mode")))))
(defcustom whitespace-global-mode-buffers (list (regexp-quote "*scratch*"))
(defcustom whitespace-global-mode-buffers (list (rx bos "*scratch*" eos))
"Buffer name regexps where global `whitespace-mode' can be auto-enabled.
The value is a list of regexps. Set this custom option when you need
`whitespace-mode' in special buffers like *Org Src*."
:type '(list (regexp :tag "Regexp matching buffer name"))
`whitespace-mode' in special buffers like \"*Org Src*\"."
:type '(repeat (regexp :tag "Regexp matching buffer name"))
:version "31.1")
(defcustom whitespace-action nil
@ -1049,14 +1049,13 @@ See also `whitespace-newline' and `whitespace-display-mappings'."
;; ...we have a display (not running a batch job)
(not noninteractive)
;; ...the buffer is not internal (name starts with a space)
(not (eq (aref (buffer-name) 0) ?\ ))
(not (eq (aref (buffer-name) 0) ?\s))
;; ...the buffer is not special (name starts with *)
(or (not (eq (aref (buffer-name) 0) ?*))
;; except the scratch buffer.
(seq-find
(lambda (re)
(string-match-p re (buffer-name)))
whitespace-global-mode-buffers))))
;; except, e.g., the scratch buffer.
(any (lambda (re)
(string-match-p re (buffer-name)))
whitespace-global-mode-buffers))))
"Predicate to decide which buffers obey `global-whitespace-mode'.
This function is called with no argument and should return non-nil
if the current buffer should obey `global-whitespace-mode'.

View file

@ -1010,6 +1010,14 @@ and may be called only if no window on SIDE exists yet."
(cons `(dedicated . ,(or display-buffer-mark-dedicated 'side))
alist))))
(when window
;; Protect the sibling (the main-window group) from recombination.
;; Without this, deleting a side window can flatten the group into
;; the root, causing subsequent side windows on other sides to be
;; placed incorrectly (Bug#80665).
(when-let* ((sibling (or (window-prev-sibling window)
(window-next-sibling window)))
((window-child sibling)))
(set-window-combination-limit sibling t))
;; Initialize `window-side' parameter of new window to SIDE and
;; make that parameter persistent.
(set-window-parameter window 'window-side side)

View file

@ -509,16 +509,14 @@ enable, ?l to disable)."
"Enable xterm mouse tracking on TERMINAL."
(when (and xterm-mouse-mode (eq t (terminal-live-p terminal))
;; Avoid the initial terminal which is not a termcap device.
;; FIXME: is there more elegant way to detect the initial
;; terminal?
(not (string= (terminal-name terminal) "initial_terminal")))
(not (frame-initial-p terminal)))
(unless (terminal-parameter terminal 'xterm-mouse-mode)
;; Simulate selecting a terminal by selecting one of its frames
;; so that we can set the terminal-local `input-decode-map'.
;; Use the tty-top-frame to avoid accidentally making an invisible
;; child frame visible by selecting it (bug#79960).
;; The test for match mode is here because xt-mouse-tests run in
;; match mode, and there is no top-frame in that case.
;; The test for batch mode is here because xt-mouse-tests run in
;; batch mode, and there is no top-frame in that case.
(with-selected-frame (if noninteractive
(car (frame-list))
(tty-top-frame terminal))

View file

@ -367,6 +367,8 @@ bidi_isolate_fmt_char (bidi_type_t ch_type)
return (ch_type == LRI || ch_type == RLI || ch_type == PDI || ch_type == FSI);
}
static void bidi_initialize (void);
/* Return the mirrored character of C, if it has one. If C has no
mirrored counterpart, return C.
Note: The conditions in UAX#9 clause L4 regarding the surrounding
@ -381,6 +383,14 @@ bidi_mirror_char (int c)
if (c < 0 || c > MAX_CHAR)
emacs_abort ();
/* We can be called at the very beginning of init_iterator, via
produce_special_glyphs, and the first such call in a session might
happen when the bidi-mirroring table was not yet initialized. Make
sure we do this now. */
if (!CHAR_TABLE_P (bidi_mirror_table)
&& !bidi_initialized)
bidi_initialize ();
val = CHAR_TABLE_REF (bidi_mirror_table, c);
if (FIXNUMP (val))
{

View file

@ -799,7 +799,7 @@ Optional 4th and 5th arguments FROM-CODE and TO-CODE specify the
range of code points (in CHARSET) of target characters on which to
map the FUNCTION. Note that these are not character codes, but code
points of CHARSET; for the difference see `decode-char' and
`list-charset-chars'. If FROM-CODE is nil or imitted, it stands for
`list-charset-chars'. If FROM-CODE is nil or omitted, it stands for
the first code point of CHARSET; if TO-CODE is nil or omitted, it
stands for the last code point of CHARSET.
@ -840,7 +840,7 @@ TO-CODE, which are CHARSET code points. */)
/* Define a charset according to the arguments. The Nth argument is
the Nth attribute of the charset (the last attribute `charset-id'
is not included). See the docstring of `define-charset' for the
detail. */
details. */
DEFUN ("define-charset-internal", Fdefine_charset_internal,
Sdefine_charset_internal, charset_arg_max, MANY, 0,
@ -1530,7 +1530,7 @@ BEG and END are buffer positions.
Optional arg TABLE if non-nil is a translation table to look up.
If the current buffer is unibyte, the returned list may contain
only `ascii', `eight-bit-control', and `eight-bit-graphic'. */)
only `ascii' and `eight-bit'. */)
(Lisp_Object beg, Lisp_Object end, Lisp_Object table)
{
Lisp_Object charsets;
@ -1581,7 +1581,7 @@ DEFUN ("find-charset-string", Ffind_charset_string, Sfind_charset_string,
Optional arg TABLE if non-nil is a translation table to look up.
If STR is unibyte, the returned list may contain
only `ascii', `eight-bit-control', and `eight-bit-graphic'. */)
only `ascii' and `eight-bit'. */)
(Lisp_Object str, Lisp_Object table)
{
CHECK_STRING (str);
@ -2036,7 +2036,7 @@ ASCII characters are an exception: for them, this function always
returns `ascii'.
If optional 2nd arg RESTRICTION is non-nil, it is a list of charsets
from which to find the charset. It may also be a coding system. In
that case, find the charset from what supported by that coding system. */)
that case, find the charset in those supported by that coding system. */)
(Lisp_Object ch, Lisp_Object restriction)
{
struct charset *charset;

View file

@ -78,7 +78,7 @@ sub_char_table_ref_and_range (Lisp_Object, int, int *, int *,
/* Nonzero iff OBJ is a string representing uniprop values of 128
succeeding characters (the bottom level of a char-table) by a
compressed format. We are sure that no property value has a string
starting with '\001' nor '\002'. */
starting with '\001' or '\002'. */
#define UNIPROP_COMPRESSED_FORM_P(OBJ) \
(STRINGP (OBJ) && SCHARS (OBJ) > 0 \
&& ((SREF (OBJ, 0) == 1 || (SREF (OBJ, 0) == 2))))

View file

@ -6826,8 +6826,7 @@ FILE = nil means just close any termscript file currently open. */)
{
struct tty_display_info *tty;
if (! FRAME_TERMCAP_P (SELECTED_FRAME ())
&& ! FRAME_MSDOS_P (SELECTED_FRAME ()))
if (!is_tty_frame (SELECTED_FRAME ()))
error ("Current frame is not on a tty device");
tty = CURTTY ();
@ -7394,7 +7393,7 @@ init_display_interactive (void)
t = init_tty (0, terminal_type, 1); /* Errors are fatal. */
/* Convert the initial frame to use the new display. */
if (f->output_method != output_initial)
if (!FRAME_INITIAL_P (f))
emacs_abort ();
f->output_method = t->type;
f->terminal = t;
@ -7404,7 +7403,7 @@ init_display_interactive (void)
f->output_data.tty = &the_only_tty_output;
f->output_data.tty->display_info = &the_only_display_info;
#else
if (f->output_method == output_termcap)
if (FRAME_TERMCAP_P (f))
create_tty_output (f);
#endif
t->display_info.tty->top_frame = selected_frame;

View file

@ -681,8 +681,7 @@ dos_cleanup (void)
{
struct frame *sf = XFRAME (selected_frame);
if (FRAME_LIVE_P (sf)
&& (FRAME_MSDOS_P (sf) || FRAME_TERMCAP_P (sf)))
if (FRAME_LIVE_P (sf) && is_tty_frame (sf))
{
tty = CURTTY ();
if (tty->termscript)

View file

@ -774,6 +774,9 @@ Do not expand PREFIX; a non-absolute PREFIX is relative to the Emacs
working directory. If TEXT is a string, insert it into the newly
created file.
On Posix systems, the file/directory is created with access mode bits
that limit access to the current user.
Signal an error if the file could not be created.
This function does not grok magic file names. */)

View file

@ -214,7 +214,7 @@ frame_inhibit_resize (struct frame *f, bool horizontal, Lisp_Object parameter)
&& !NILP (fullscreen) && !EQ (fullscreen, Qfullheight))
|| (!horizontal
&& !NILP (fullscreen) && !EQ (fullscreen, Qfullwidth))
|| FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))));
|| is_tty_frame (f))));
}
@ -349,8 +349,6 @@ If FRAME is nil, use the selected frame.
Return nil if the id has not been set. */)
(Lisp_Object frame)
{
if (NILP (frame))
frame = selected_frame;
struct frame *f = decode_live_frame (frame);
if (f->id == 0)
return Qnil;
@ -562,7 +560,7 @@ frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal,
/* Don't allow too small height of text-mode frames, or else cm.c
might abort in cmcheckmagic. */
if ((FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) && NILP (horizontal))
if (is_tty_frame (f) && NILP (horizontal))
{
int min_height = (FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f)
+ FRAME_WANTS_MODELINE_P (f)
@ -1573,7 +1571,7 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent,
f->output_data.tty->display_info = &the_only_display_info;
if (!inhibit_window_system
&& (!FRAMEP (selected_frame) || !FRAME_LIVE_P (XFRAME (selected_frame))
|| XFRAME (selected_frame)->output_method == output_msdos_raw))
|| FRAME_MSDOS_P (XFRAME (selected_frame))))
f->output_method = output_msdos_raw;
else
f->output_method = output_termcap;
@ -1763,13 +1761,12 @@ affects all frames on the same terminal device. */)
struct frame *sf = SELECTED_FRAME ();
#ifdef MSDOS
if (sf->output_method != output_msdos_raw
&& sf->output_method != output_termcap)
if (!is_tty_frame (sf))
emacs_abort ();
#else /* not MSDOS */
#ifdef WINDOWSNT /* This should work now! */
if (sf->output_method != output_termcap)
if (!FRAME_TERMCAP_P (sf))
error ("Not using an ASCII terminal now; cannot make a new ASCII frame");
#endif
#endif /* not MSDOS */
@ -1986,7 +1983,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
if (!for_deletion && FRAME_HAS_MINIBUF_P (sf))
resize_mini_window (XWINDOW (FRAME_MINIBUF_WINDOW (sf)), 1);
if (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))
if (is_tty_frame (f))
{
struct tty_display_info *tty = FRAME_TTY (f);
Lisp_Object top_frame = tty->top_frame;
@ -2800,7 +2797,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
&& FRAME_LIVE_P (f1)
&& !FRAME_TOOLTIP_P (f1))
{
if (FRAME_TERMCAP_P (f1) || FRAME_MSDOS_P (f1))
if (is_tty_frame (f1))
{
Lisp_Object top_frame = FRAME_TTY (f1)->top_frame;

View file

@ -2453,7 +2453,7 @@ read_decoded_event_from_main_queue (struct timespec *end_time,
#else
struct frame *frame = XFRAME (selected_frame);
struct terminal *terminal = frame->terminal;
if (!((FRAME_TERMCAP_P (frame) || FRAME_MSDOS_P (frame))
if (!(is_tty_frame (frame)
/* Don't apply decoding if we're just reading a raw event
(e.g. reading bytes sent by the xterm to specify the position
of a mouse click). */
@ -13032,7 +13032,7 @@ The elements of this list correspond to the arguments of
Lisp_Object interrupt = interrupt_input ? Qt : Qnil;
Lisp_Object flow, meta;
if (FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf))
if (is_tty_frame (sf))
{
flow = FRAME_TTY (sf)->flow_control ? Qt : Qnil;
meta = (FRAME_TTY (sf)->meta_key == 2

View file

@ -5754,7 +5754,7 @@ extern void *w32_daemon_event;
/* True if handling a fatal error already. */
extern bool fatal_error_in_progress;
/* True means don't do use window-system-specific display code. */
/* True means don't use window-system-specific display code. */
extern bool inhibit_window_system;
/* True means that a filter or a sentinel is running. */
extern bool running_asynch_code;

View file

@ -405,8 +405,7 @@ single_menu_item (Lisp_Object key, Lisp_Object item, Lisp_Object dummy, void *sk
}
}
if ((FRAME_TERMCAP_P (XFRAME (Vmenu_updating_frame))
|| FRAME_MSDOS_P (XFRAME (Vmenu_updating_frame)))
if (is_tty_frame (XFRAME (Vmenu_updating_frame))
&& !NILP (map))
/* Indicate visually that this is a submenu. */
{

View file

@ -1787,7 +1787,7 @@ internal_terminal_init (void)
#endif
/* If this is the initial terminal, we are done here. */
if (sf->output_method == output_initial)
if (FRAME_INITIAL_P (sf))
return;
internal_terminal

View file

@ -72,6 +72,12 @@ Updated by Christian Limpach (chris@nice.ch)
#include "macfont.h"
#include <Carbon/Carbon.h>
#include <IOSurface/IOSurface.h>
/* ApplicationServices provides the macOS accessibility Zoom API
UAZoomEnabled and UAZoomChangeFocus (UniversalAccess framework).
Carbon.h already pulls in ApplicationServices on most SDK versions,
but the explicit import makes the dependency visible and guards
against SDK changes. */
#import <ApplicationServices/ApplicationServices.h>
#endif
static EmacsMenu *dockMenu;
@ -1086,6 +1092,126 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
[view lockFocus];
}
/* --------------------------------------------------------------------------
macOS Accessibility Zoom Support
-------------------------------------------------------------------------- */
#ifdef NS_IMPL_COCOA
static BOOL ns_is_UAZoomEnabled = NO;
static unsigned long ns_UAZoomEnabled_last_called_time_ns = 0;
static const unsigned long NS_UAZOOMENABLED_CACHE_INTERVAL_NS =
(unsigned long)(500 * NSEC_PER_MSEC); /* 500ms. */
static NSTimeInterval NS_UAZOOMENABLED_DEFER_INTERVAL_SECS = 0.2; /* 200ms. */
static NSTimer *ns_deferred_UAZoomChangeFocus_timer = nil;
static BOOL
ns_ua_zoom_enabled_p (void)
/* --------------------------------------------------------------------------
Return the cached result of UAZoomEnabled. Refresh the cache every
NS_UAZOOMENABLED_CACHE_INTERVAL_NS nanoseconds.
We cache the result to avoid the macOS Mach IPC Accessibility Server
round trip cost on every Emacs cursor update. Since enabling Zoom
requires an explicit user UI action that takes real user time, the
cache TTL should be invisible to the user.
Use clock_gettime_nsec_np not CFAbsoluteTimeGetCurrent which depends
on the wall clock which can be reset by the user or by NTP.
Main-thread-only and called from ns_update_end, below.
-------------------------------------------------------------------------- */
{
/* User-space equivalent to mach_absolute_time. */
unsigned long now_ns = clock_gettime_nsec_np (CLOCK_UPTIME_RAW);
if (now_ns - ns_UAZoomEnabled_last_called_time_ns
> NS_UAZOOMENABLED_CACHE_INTERVAL_NS)
{
ns_is_UAZoomEnabled = UAZoomEnabled ();
ns_UAZoomEnabled_last_called_time_ns = now_ns;
}
return ns_is_UAZoomEnabled;
}
static inline CGRect
ns_cg_rect_flip_y (CGRect r)
/* --------------------------------------------------------------------------
Convert a CGRect from Cocoa screen coordinates (origin at bottom-left
of the primary display) to CoreGraphics coordinates (origin at
top-left of the primary display). CoreGraphics defines its
coordinate origin at the top-left corner of the primary display and
all screens share this global coordinate space, so the flip always
uses the primary display height regardless of which screen R is on.
-------------------------------------------------------------------------- */
{
CGDirectDisplayID mainID = CGMainDisplayID ();
if (mainID == kCGNullDirectDisplay)
return r;
CGFloat primaryH = CGDisplayBounds (mainID).size.height;
if (primaryH <= 0)
return r;
r.origin.y = primaryH - r.origin.y - r.size.height;
return r;
}
/* Cache cursor rects to call UAZoomChangeFocus only when the cursor
position has changed, not merely when the cursor is blinking.
See ns_draw_window_cursor and ns_update_end. */
static NSRect ns_UAZoom_cursor_rect_new;
static NSRect ns_UAZoom_cursor_rect_old;
/* Track Zoom state per display cycle. Update the macOS Zoom cursor
position when Zoom transitions to enabled. */
static BOOL ns_update_was_UAZoomEnabled = NO;
static void
ns_UAZoomChangeFocus (EmacsView *view, BOOL force)
/* --------------------------------------------------------------------------
Advise macOS Accessibility Zoom UAZoomChangeFocus of a potentially
new cursor position. Force an updated position when Zoom transitions
to enabled, or when the frame gets focus.
-------------------------------------------------------------------------- */
{
if (ns_ua_zoom_enabled_p ())
{
force = force || !ns_update_was_UAZoomEnabled;
ns_update_was_UAZoomEnabled = YES;
if (NSIsEmptyRect (ns_UAZoom_cursor_rect_new))
return;
if (force || !NSEqualRects (ns_UAZoom_cursor_rect_new,
ns_UAZoom_cursor_rect_old))
{
ns_UAZoom_cursor_rect_old = ns_UAZoom_cursor_rect_new;
NSRect windowRect = [view convertRect:ns_UAZoom_cursor_rect_new
toView:nil];
NSRect screenRect = [[view window] convertRectToScreen:windowRect];
CGRect cgRect = ns_cg_rect_flip_y (NSRectToCGRect (screenRect));
/* Some versions of macOS can ignore tiny rects, so we
slightly expand a tiny one. Since we care mostly about its
origin, this should be innocuous. */
cgRect.size.width = MAX (cgRect.size.width, 6);
cgRect.size.height = MAX (cgRect.size.height, 10);
if (force)
{
/* UAZoomChangeFocus needs old and new cursor positions to
be different, and also it sometimes needs a kick. In
both cases, we fake a cursor move followed by the real
cursor move. */
CGRect cgRectJiggle = CGRectOffset (cgRect, 1.0, 1.0);
if (UAZoomChangeFocus (&cgRectJiggle, NULL,
kUAZoomFocusTypeInsertionPoint))
NSLog (@"UAZoomChangeFocus jiggle failed");
}
if (UAZoomChangeFocus (&cgRect, NULL,
kUAZoomFocusTypeInsertionPoint))
NSLog (@"UAZoomChangeFocus failed");
NSAccessibilityPostNotification
(view, NSAccessibilityFocusedUIElementChangedNotification);
}
}
else
ns_update_was_UAZoomEnabled = NO;
}
#endif /* NS_IMPL_COCOA */
static void
ns_update_end (struct frame *f)
@ -1108,6 +1234,10 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
[[view window] flushWindow];
#endif
#ifdef NS_IMPL_COCOA
ns_UAZoomChangeFocus (view, false);
#endif
unblock_input ();
ns_updating_frame = NULL;
}
@ -3238,6 +3368,16 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
/* Prevent the cursor from being drawn outside the text area. */
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
#ifdef NS_IMPL_COCOA
/* Cache the cursor rect for macOS Accessibility Zoom integration (see
ns_update_end). Only store the rect for the active cursor ---
inactive windows must not overwrite the value because redisplay may
draw multiple windows per frame and the drawing order is not
guaranteed. */
if (active_p)
ns_UAZoom_cursor_rect_new = r;
#endif
ns_focus (f, NULL, 0);
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
@ -6384,6 +6524,14 @@ - (void)applicationDidFinishLaunching: (NSNotification *)notification
}
#endif
#ifdef NS_IMPL_COCOA
/* Is accessibility enabled for this process/bundle? */
if (AXIsProcessTrusted())
NSLog (@"Emacs is macOS AXIsProcessTrusted");
else
NSLog (@"Emacs is not macOS AXIsProcessTrusted");
#endif
ns_send_appdefined (-2);
}
@ -7300,6 +7448,12 @@ - (NSRect) firstRectForCharacterRange: (NSRange) range
return [self firstRectForCharacterRange: range];
}
- (NSRect)accessibilityFrame
{
EmacsView *view = FRAME_NS_VIEW (*emacsframe);
return [[view window] convertRectToScreen: ns_UAZoom_cursor_rect_new];
}
#endif /* NS_IMPL_COCOA */
/***********************************************************************
@ -8257,12 +8411,48 @@ - (void)windowDidBecomeKey /* for direct calls */
ns_frame_rehighlight (*emacsframe);
[self adjustEmacsFrameRect];
#ifdef NS_IMPL_COCOA
EmacsView *view = FRAME_NS_VIEW (*emacsframe);
/* Make sure we have focus and the timer isn't already scheduled. */
if (self.window.firstResponder == view
&& !ns_deferred_UAZoomChangeFocus_timer)
{
/* Calls to ns_UAZoomChangeFocus are synchronous. We defer the
call to give macOS time to finish window compositing or the
calls can be silently ignored by the Zoom daemon and with no
errors reported. This also helps ensure ns_draw_window_cursor
has populated ns_UAZoom_cursor_rect_new. The 200 ms delay was
chosen as a balance between macOS headroom and user
perception. */
ns_deferred_UAZoomChangeFocus_timer
= [[NSTimer
scheduledTimerWithTimeInterval:
NS_UAZOOMENABLED_DEFER_INTERVAL_SECS
target: self
selector:
@selector (deferred_UAZoomChangeFocus_handler:)
userInfo: 0
repeats: NO]
retain];
}
#endif
event.kind = FOCUS_IN_EVENT;
XSETFRAME (event.frame_or_window, *emacsframe);
kbd_buffer_store_event (&event);
ns_send_appdefined (-1); // Kick main loop
}
#ifdef NS_IMPL_COCOA
- (void)deferred_UAZoomChangeFocus_handler: (NSTimer *)timer
{
EmacsView *view = FRAME_NS_VIEW (*emacsframe);
ns_UAZoomChangeFocus (view, true);
[ns_deferred_UAZoomChangeFocus_timer invalidate];
[ns_deferred_UAZoomChangeFocus_timer release];
ns_deferred_UAZoomChangeFocus_timer = nil;
}
#endif
- (void)windowDidResignKey: (NSNotification *)notification
/* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
@ -8365,6 +8555,13 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f
FRAME_NS_VIEW (f) = self;
*emacsframe = f;
#ifdef NS_IMPL_COCOA
/* macOS Accessibility Zoom Support. */
ns_UAZoom_cursor_rect_new = NSZeroRect;
ns_UAZoom_cursor_rect_old = NSZeroRect;
#endif
#ifdef NS_IMPL_COCOA
old_title = 0;
maximizing_resize = NO;

View file

@ -703,33 +703,16 @@ pgtk_set_offset (struct frame *f, int xoff, int yoff, int change_gravity)
static void
pgtk_set_window_size (struct frame *f, bool change_gravity,
int width, int height)
int pixelwidth, int pixelheight)
/* --------------------------------------------------------------------------
Adjust window pixel size based on given character grid size
Impl is a bit more complex than other terms, need to do some
internal clipping.
Adjust window pixel size based on given width and height.
-------------------------------------------------------------------------- */
{
int pixelwidth, pixelheight;
block_input ();
gtk_widget_get_size_request (FRAME_GTK_WIDGET (f), &pixelwidth,
&pixelheight);
pixelwidth = width;
pixelheight = height;
for (GtkWidget * w = FRAME_GTK_WIDGET (f); w != NULL;
w = gtk_widget_get_parent (w))
{
gint wd, hi;
gtk_widget_get_size_request (w, &wd, &hi);
}
f->output_data.pgtk->preferred_width = pixelwidth;
f->output_data.pgtk->preferred_height = pixelheight;
xg_wm_set_size_hint (f, 0, 0);
xg_frame_set_char_size (f, pixelwidth, pixelheight);
gtk_widget_queue_resize (FRAME_WIDGET (f));
@ -5722,10 +5705,11 @@ pgtk_focus_changed (gboolean is_enter, int state,
/* Don't stop displaying the initial startup message
for a switch-frame event we don't need. */
/* When run as a daemon, Vterminal_frame is always NIL. */
/* When run as a daemon, Vterminal_frame is always nil.
FIXME: Isn't it actually the other way around? */
bufp->ie.arg = (((NILP (Vterminal_frame)
|| !FRAME_PGTK_P (XFRAME (Vterminal_frame))
|| EQ (Fdaemonp (), Qt))
|| IS_DAEMON)
&& CONSP (Vframe_list)
&& !NILP (XCDR (Vframe_list))) ? Qt : Qnil);
bufp->ie.kind = FOCUS_IN_EVENT;

View file

@ -1341,8 +1341,7 @@ init_sys_modes (struct tty_display_info *tty_out)
frame_garbaged = 1;
FOR_EACH_FRAME (tail, frame)
{
if ((FRAME_TERMCAP_P (XFRAME (frame))
|| FRAME_MSDOS_P (XFRAME (frame)))
if (is_tty_frame (XFRAME (frame))
&& FRAME_TTY (XFRAME (frame)) == tty_out)
FRAME_GARBAGED_P (XFRAME (frame)) = 1;
}

View file

@ -2969,9 +2969,7 @@ Gpm-mouse can only be activated for one tty at a time. */)
(void)
{
struct frame *f = SELECTED_FRAME ();
struct tty_display_info *tty
= ((f)->output_method == output_termcap
? (f)->terminal->display_info.tty : NULL);
struct tty_display_info *tty = FRAME_TERMCAP_P (f) ? FRAME_TTY (f) : NULL;
Gpm_Connect connection;
if (!tty)
@ -3017,9 +3015,7 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop,
(void)
{
struct frame *f = SELECTED_FRAME ();
struct tty_display_info *tty
= ((f)->output_method == output_termcap
? (f)->terminal->display_info.tty : NULL);
struct tty_display_info *tty = FRAME_TERMCAP_P (f) ? FRAME_TTY (f) : NULL;
if (!tty || gpm_tty != tty)
return Qnil; /* Not activated on this terminal, nothing to do. */
@ -4214,7 +4210,7 @@ tty_free_frame_resources (struct frame *f)
static void
tty_free_frame_resources (struct frame *f)
{
eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
eassert (is_tty_frame (f));
free_frame_faces (f);
/* Deleting a child frame means we have to thoroughly redisplay its
root frame to make sure the child disappears from the display. */

View file

@ -251,8 +251,8 @@ decode_live_terminal (Lisp_Object terminal)
return t;
}
/* Like decode_terminal, but ensure that the resulting terminal object refers
to a text-based terminal device. */
/* Like decode_live_terminal, but ensure that the resulting terminal
object refers to a text-based terminal device. */
struct terminal *
decode_tty_terminal (Lisp_Object terminal)
@ -508,6 +508,25 @@ return values. */)
}
}
DEFUN ("frame-initial-p", Fframe_initial_p, Sframe_initial_p, 0, 1, 0,
doc: /* Return non-nil if FRAME is the initial frame.
That is, the initial text frame used internally during daemon mode,
batch mode, and the early stages of startup.
If FRAME is a terminal object, return non-nil if it holds
the initial frame. FRAME defaults to the selected frame. */)
(Lisp_Object frame)
{
if (NILP (frame))
frame = selected_frame;
if (FRAMEP (frame))
{
struct frame *f = XFRAME (frame);
return FRAME_LIVE_P (f) && FRAME_INITIAL_P (f) ? Qt : Qnil;
}
struct terminal *t = decode_terminal (frame);
return t && t->type == output_initial ? Qt : Qnil;
}
DEFUN ("terminal-list", Fterminal_list, Sterminal_list, 0, 0, 0,
doc: /* Return a list of all terminal devices. */)
(void)
@ -680,8 +699,6 @@ init_initial_terminal (void)
#else
initial_terminal_lisp = make_lisp_ptr (create_terminal (output_initial, NULL), Lisp_Vectorlike);
#endif
/* Note: menu-bar.el:menu-bar-update-buffers knows about this
special name of the initial terminal. */
initial_terminal->name = xstrdup ("initial_terminal");
initial_terminal->kboard = initial_kboard;
initial_terminal->delete_terminal_hook = &delete_initial_terminal;
@ -725,6 +742,7 @@ or some time later. */);
Vdelete_terminal_functions = Qnil;
DEFSYM (Qterminal_live_p, "terminal-live-p");
DEFSYM (Qframe_initial_p, "frame-initial-p");
DEFSYM (Qdelete_terminal_functions, "delete-terminal-functions");
DEFSYM (Qrun_hook_with_args, "run-hook-with-args");
@ -734,6 +752,7 @@ or some time later. */);
defsubr (&Sdelete_terminal);
defsubr (&Sframe_terminal);
defsubr (&Sterminal_live_p);
defsubr (&Sframe_initial_p);
defsubr (&Sterminal_list);
defsubr (&Sterminal_name);
defsubr (&Sterminal_parameters);

View file

@ -177,7 +177,7 @@ get_frame_dc (struct frame *f)
HGDIOBJ obj;
struct w32_output *output;
if (f->output_method != output_w32)
if (!FRAME_W32_P (f))
emacs_abort ();
enter_crit ();

View file

@ -13665,7 +13665,7 @@ clear_garbaged_frames (void)
selected frame, and might leave the selected
frame with corrupted display, if it happens not
to be marked garbaged. */
&& !(f != sf && (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))))
&& !(f != sf && is_tty_frame (f)))
redraw_frame (f);
else
clear_current_matrices (f);
@ -16653,11 +16653,8 @@ hscroll_window_tree (Lisp_Object window)
}
}
if (cursor_row->truncated_on_left_p)
{
/* On TTY frames, don't count the left truncation glyph. */
struct frame *f = XFRAME (WINDOW_FRAME (w));
x_offset -= (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
}
/* On TTY frames, don't count the left truncation glyph. */
x_offset -= is_tty_frame (XFRAME (WINDOW_FRAME (w)));
text_area_width = window_box_width (w, TEXT_AREA);
@ -17391,7 +17388,7 @@ redisplay_internal (void)
windows_or_buffers_changed = 47;
struct frame *previous_frame;
if ((FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf))
if (is_tty_frame (sf)
&& (previous_frame = FRAME_TTY (sf)->previous_frame,
previous_frame != sf))
{
@ -17836,8 +17833,7 @@ redisplay_internal (void)
}
retry_frame:
if (FRAME_WINDOW_P (f)
|| FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f) || f == sf)
if (FRAME_WINDOW_P (f) || is_tty_frame (f) || f == sf)
{
/* Only GC scrollbars when we redisplay the whole frame. */
bool gcscrollbars = f->redisplay || !REDISPLAY_SOME_P ();
@ -32864,6 +32860,8 @@ produce_special_glyphs (struct it *it, enum display_element_type what,
/* Mirror for R2L. */
if (direction == R2L)
{
face_id = GLYPH_CODE_FACE (gc);
/* Try bidi mirroring first. */
int c = bidi_mirror_char (GLYPH_CODE_CHAR (gc));
@ -32877,16 +32875,23 @@ produce_special_glyphs (struct it *it, enum display_element_type what,
{
c = XFIXNUM (val);
/* If something goes wrong defaults to '/'. */
/* If something goes wrong, fall back to '/'. */
if (CHAR_VALID_P (c))
SET_GLYPH (glyph, c, face_id);
else
SET_GLYPH (glyph, '/', face_id);
}
else
SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
}
else
{
struct face *face = FACE_FROM_ID (it->f, face_id);
int id = FACE_FOR_CHAR (it->f, face, c, -1, Qnil);
/* Bidi mirroring. */
SET_GLYPH (glyph, c, face_id);
SET_GLYPH (glyph, c, id);
}
}
else
/* No mirroring. */
@ -32925,6 +32930,8 @@ produce_special_glyphs (struct it *it, enum display_element_type what,
if (((it->bidi_it.paragraph_dir == R2L) && !left_edge_p) ||
((it->bidi_it.paragraph_dir == L2R) && left_edge_p))
{
face_id = GLYPH_CODE_FACE (gc);
/* Try bidi mirroring first. */
int c = bidi_mirror_char (GLYPH_CODE_CHAR (gc));
@ -32938,12 +32945,14 @@ produce_special_glyphs (struct it *it, enum display_element_type what,
{
c = XFIXNUM (val);
/* If something goes wrong defaults to '$'. */
/* If something goes wrong, fall back to '$'. */
if (CHAR_VALID_P (c))
SET_GLYPH (glyph, c, face_id);
else
SET_GLYPH (glyph, '$', face_id);
}
else
SET_GLYPH_FROM_GLYPH_CODE (glyph, gc);
}
else
{

View file

@ -5827,7 +5827,7 @@ face for italic. */)
}
/* Dispatch to the appropriate handler. */
if (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))
if (is_tty_frame (f))
supports = tty_supports_face_attributes_p (f, attrs, def_face);
#ifdef HAVE_WINDOW_SYSTEM
else
@ -6121,7 +6121,7 @@ realize_default_face (struct frame *f)
ASET (lface, LFACE_FOREGROUND_INDEX, XCDR (color));
else if (FRAME_WINDOW_P (f))
return false;
else if (FRAME_INITIAL_P (f) || FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))
else if (FRAME_INITIAL_P (f) || is_tty_frame (f))
ASET (lface, LFACE_FOREGROUND_INDEX, build_string (unspecified_fg));
else
emacs_abort ();
@ -6136,7 +6136,7 @@ realize_default_face (struct frame *f)
ASET (lface, LFACE_BACKGROUND_INDEX, XCDR (color));
else if (FRAME_WINDOW_P (f))
return false;
else if (FRAME_INITIAL_P (f) || FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))
else if (FRAME_INITIAL_P (f) || is_tty_frame (f))
ASET (lface, LFACE_BACKGROUND_INDEX, build_string (unspecified_bg));
else
emacs_abort ();
@ -6247,7 +6247,7 @@ realize_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE],
if (FRAME_WINDOW_P (cache->f))
face = realize_gui_face (cache, attrs);
else if (FRAME_TERMCAP_P (cache->f) || FRAME_MSDOS_P (cache->f))
else if (is_tty_frame (cache->f))
face = realize_tty_face (cache, attrs);
else if (FRAME_INITIAL_P (cache->f))
{
@ -6760,7 +6760,7 @@ realize_tty_face (struct face_cache *cache,
struct frame *f = cache->f;
/* Frame must be a termcap frame. */
eassert (FRAME_TERMCAP_P (cache->f) || FRAME_MSDOS_P (cache->f));
eassert (is_tty_frame (cache->f));
/* Allocate a new realized face. */
face = make_realized_face (attrs);

View file

@ -91,7 +91,10 @@ This function is intended to be set to `auth-source-debug'."
((symbol-function 'auth-source-pass-entries) (lambda () (mapcar #'car ,store))))
(let ((auth-source-debug #'auth-source-pass--debug)
(auth-source-pass--debug-log nil)
(auth-source-pass--parse-log nil))
(auth-source-pass--parse-log nil)
;; Any existing directory will do, since we shouldn't do I/O
;; except for the guard in `auth-source-pass-search'.
(auth-source-pass-filename default-directory))
,@body)))
(defun auth-source-pass--explain-match-entry-p (entry hostname &optional user port)

View file

@ -90,7 +90,7 @@
(erase-buffer))
(setopt cus-edit-test-foo1 :foo)
(buffer-substring-no-properties (point-min) (point-max)))))
(should (string-search "Value `:foo' for variable `cus-edit-test-foo1' does not match its type \"number\""
(should (string-search "Value does not match cus-edit-test-foo1's type `number': :foo\n"
warn-txt))))
(defcustom cus-edit-test-bug63290-option nil

View file

@ -658,5 +658,155 @@ The current directory at call time should not affect the result (Bug#50630)."
(let ((default-directory test-dir-other))
(files-tests--insert-directory-shows-given-free test-dir)))))
(ert-deftest dired-test-filename-with-newline-1 () ; bug#79528, bug#80499
"Test handling of file name with literal embedded newline."
;; File names with embedded newlines are not allowed on MS-Windows and
;; MS-DOS.
(skip-when (memq system-type '(windows-nt ms-dos)))
(with-current-buffer "*Messages*"
(let ((inhibit-read-only t))
(erase-buffer)))
(let* ((dired-auto-toggle-b-switch nil)
(dir (ert-resource-file
(file-name-as-directory "filename-with-newline")))
(file (concat dir "filename\nwith newline"))
(buf (progn (make-empty-file file t)
(dired (file-name-directory file))))
(warnbuf (get-buffer "*Warnings*")))
(should (dired--filename-with-newline-p))
(let ((beg (point)) ; beginning of file name
(_ (dired-move-to-end-of-filename)))
(should (search-backward "with newline")) ; literal space in file name
(should (search-backward "\n" beg))) ; literal newline in file name
(if noninteractive
(with-current-buffer "*Messages*"
(goto-char (point-min))
(should (search-forward
"Warning (dired): Literal newline in file name.")))
(should (get-buffer-window warnbuf))
(with-current-buffer warnbuf
(goto-char (point-min))
(should (string-match
(regexp-quote "Warning (dired): Literal newline in file name.")
(buffer-substring (pos-bol) (pos-eol))))))
(kill-buffer buf)
(kill-buffer warnbuf)
(delete-directory dir t)))
(ert-deftest dired-test-filename-with-newline-2 () ; bug#79528, bug#80499
"Test handling of file name with embedded newline using `b' switch."
;; File names with embedded newlines are not allowed on MS-Windows and
;; MS-DOS.
(skip-when (memq system-type '(windows-nt ms-dos)))
(with-current-buffer "*Messages*"
(let ((inhibit-read-only t))
(erase-buffer)))
(let* ((dired-auto-toggle-b-switch t)
(dir (ert-resource-file
(file-name-as-directory "filename-with-newline")))
(file (concat dir "filename\nwith newline"))
(buf (progn (make-empty-file file t)
(dired-noselect (file-name-directory file))))
(warnbuf (get-buffer "*Warnings*")))
(with-current-buffer buf
(should (dired--filename-with-newline-p))
(dired--toggle-b-switch)
(let ((beg (point)) ; beginning of file name
(_ (dired-move-to-end-of-filename)))
(should (search-backward "with\\ newline")) ; result of ls -b switch
(should (search-backward "\\n" beg)))) ; result of ls -b switch
(if noninteractive
(with-current-buffer "*Messages*"
(goto-char (point-min))
(should-error (search-forward
"Warning (dired): Literal newline in file name.")))
(should-not (get-buffer "*Warnings*")))
(kill-buffer buf)
(kill-buffer warnbuf)
(delete-directory dir t)))
(ert-deftest dired-test-ls-error-message () ; bug#80499
"Test invoking `dired' on a nonexisting file.
A buffer should pop up containing the error emitted by ls. The buffer
visiting the nonexisting file should killed before `dired' returns,
hence another buffer should be returned."
(let* ((dir (ert-resource-file (file-name-as-directory "empty-dir")))
(name (concat dir "bla"))
;; Use PARENT = t in make-directory call to avoid failing if
;; the directyory already exists for some reason.
(buf (progn (make-directory dir t)
(dired name))))
;; This is for MS-Windows and MS-DOS in the default configuration.
(when (and (featurep 'ls-lisp)
(boundp 'ls-lisp-use-insert-directory-program)
(null ls-lisp-use-insert-directory-program))
(should (bufferp buf))
(should (equal (buffer-name buf) (file-name-nondirectory name)))
(with-current-buffer buf
;; 'ls-lisp' creates a Dired buffer of just 3 lines, with
;; "(No match)" on the last line
(should (string-match "(No match)" (buffer-string)))
(should (= 3 (line-number-at-pos (buffer-size) t)))))
;; This is for Posix systems and for MS-Windows/DOS when they use 'ls'.
(unless (and (featurep 'ls-lisp)
(boundp 'ls-lisp-use-insert-directory-program)
(null ls-lisp-use-insert-directory-program))
(let ((errbuf (get-buffer "*ls error*")))
(should (get-buffer-window errbuf))
(should-not (equal (buffer-name buf) (file-name-nondirectory name)))
(with-current-buffer errbuf
(should (string-match-p
(format
;; Use .* around file name to account for different
;; file-name quoting styles, or no quoting at all.
"%s: cannot access .*%s.*: No such file or directory\n"
insert-directory-program (file-name-nondirectory name))
(buffer-string))))
(kill-buffer errbuf))
(delete-directory dir t))))
(defun dired-test--filename-with-backslash-n ()
"Core of test `dired-test-filename-with-backslash-n'."
(let* ((dir (ert-resource-file
(file-name-as-directory "filename-with-backslash")))
(file (concat dir "C:\\nppdf32log\\debuglog.txt"))
(buf (progn (make-empty-file file t)
(dired-noselect (file-name-directory file))))
(warnbuf (get-buffer "*Warnings*")))
(with-current-buffer buf
(should-not (dired--filename-with-newline-p))
(dired--toggle-b-switch)
(should-not (dired--filename-with-newline-p))
(let ((fn (car (directory-files dir t
directory-files-no-dot-files-regexp))))
(should (equal fn file))))
(if noninteractive
(with-current-buffer "*Messages*"
(goto-char (point-min))
(should-error (search-forward
"Warning (dired): Literal newline in file name.")))
(should-not (get-buffer "*Warnings*")))
(kill-buffer buf)
(kill-buffer warnbuf)
(delete-directory dir t)))
(ert-deftest dired-test-filename-with-backslash-n () ; bug#80608
"Test file name containing literal backslash-n sequence.
Dired should not treat this sequence as a newline character, regardless
of the value of `dired-auto-toggle-b-switch'."
;; File names with backslashes in basename are not allowed on MS systems.
(skip-when (memq system-type '(windows-nt ms-dos)))
(with-current-buffer "*Messages*"
(let ((inhibit-read-only t))
(erase-buffer)))
(let ((dired-auto-toggle-b-switch nil))
(dired-test--filename-with-backslash-n))
(with-current-buffer "*Messages*"
(let ((inhibit-read-only t))
(erase-buffer)))
(let ((dired-auto-toggle-b-switch nil))
(dired-test--filename-with-backslash-n)))
(provide 'dired-tests)
;;; dired-tests.el ends here

Some files were not shown because too many files have changed in this diff Show more