Merge remote-tracking branch 'savannah/master' into HEAD

This commit is contained in:
Andrea Corallo 2020-05-24 10:20:23 +01:00
commit 9daffe9cfe
61 changed files with 2050 additions and 1205 deletions

View file

@ -727,6 +727,8 @@ them. Rectangle commands are useful with text in multicolumn formats,
and for changing text into or out of such formats.
@cindex mark rectangle
@cindex region-rectangle
@cindex rectangular region
To specify a rectangle for a command to work on, set the mark at one
corner and point at the opposite corner. The rectangle thus specified
is called the @dfn{region-rectangle}. If point and the mark are in

View file

@ -1326,16 +1326,17 @@ stored in the system and the available font names are defined by the
system, fontsets are defined within Emacs itself. Once you have
defined a fontset, you can use it within Emacs by specifying its name,
anywhere that you could use a single font. Of course, Emacs fontsets
can use only the fonts that the system supports. If some characters
can use only the fonts that your system supports. If some characters
appear on the screen as empty boxes or hex codes, this means that the
fontset in use for them has no font for those characters. In this
case, or if the characters are shown, but not as well as you would
like, you may need to install extra fonts. Your operating system may
have optional fonts that you can install; or you can install the GNU
Intlfonts package, which includes fonts for most supported
scripts.@footnote{If you run Emacs on X, you may need to inform the X
server about the location of the newly installed fonts with commands
such as:
like, you may need to install extra fonts or modify the fontset to use
specific fonts already installed on your system (see below). Your
operating system may have optional fonts that you can install; or you
can install the GNU Intlfonts package, which includes fonts for most
supported scripts.@footnote{If you run Emacs on X, you may need to
inform the X server about the location of the newly installed fonts
with commands such as:
@c FIXME? I feel like this may be out of date.
@c E.g., the intlfonts tarfile is ~ 10 years old.
@ -1376,14 +1377,20 @@ explicitly requested, despite its name.
@w{@kbd{M-x describe-fontset}} command. It prompts for a fontset
name, defaulting to the one used by the current frame, and then
displays all the subranges of characters and the fonts assigned to
them in that fontset.
them in that fontset. To see which fonts Emacs is using in a session
started without a specific fontset (which is what happens normally),
type @kbd{fontset-default @key{RET}} at the prompt, or just
@kbd{@key{RET}} to describe the fontset used by the current frame.
A fontset does not necessarily specify a font for every character
code. If a fontset specifies no font for a certain character, or if
it specifies a font that does not exist on your system, then it cannot
display that character properly. It will display that character as a
hex code or thin space or an empty box instead. (@xref{Text Display, ,
glyphless characters}, for details.)
hex code or thin space or an empty box instead. (@xref{Text Display,
, glyphless characters}, for details.) Or a fontset might specify a
font for some range of characters, but you may not like their visual
appearance. If this happens, you may wish to modify your fontset; see
@ref{Modifying Fontsets}, for how to do that.
@node Defining Fontsets
@section Defining Fontsets
@ -1542,10 +1549,10 @@ call this function explicitly to create a fontset.
Fontsets do not always have to be created from scratch. If only
minor changes are required it may be easier to modify an existing
fontset. Modifying @samp{fontset-default} will also affect other
fontsets that use it as a fallback, so can be an effective way of
fixing problems with the fonts that Emacs chooses for a particular
script.
fontset, usually @samp{fontset-default}. Modifying
@samp{fontset-default} will also affect other fontsets that use it as
a fallback, so can be an effective way of fixing problems with the
fonts that Emacs chooses for a particular script.
Fontsets can be modified using the function @code{set-fontset-font},
specifying a character, a charset, a script, or a range of characters
@ -1553,26 +1560,61 @@ to modify the font for, and a font specification for the font to be
used. Some examples are:
@example
;; Use Liberation Mono for latin-3 charset.
(set-fontset-font "fontset-default" 'iso-8859-3
"Liberation Mono")
;; Prefer a big5 font for han characters.
(set-fontset-font "fontset-default"
'han (font-spec :registry "big5")
nil 'prepend)
;; Use DejaVu Sans Mono as a fallback in fontset-startup
;; before resorting to fontset-default.
(set-fontset-font "fontset-startup" nil "DejaVu Sans Mono"
nil 'append)
;; Use MyPrivateFont for the Unicode private use area.
(set-fontset-font "fontset-default" '(#xe000 . #xf8ff)
"MyPrivateFont")
;; Use Liberation Mono for latin-3 charset.
(set-fontset-font "fontset-default" 'iso-8859-3
"Liberation Mono")
;; Use DejaVu Sans Mono as a fallback in fontset-startup
;; before resorting to fontset-default.
(set-fontset-font "fontset-startup" nil "DejaVu Sans Mono"
nil 'append)
@end example
@noindent
@xref{Fontsets, , , elisp, GNU Emacs Lisp Reference Manual}, for more
details about using the @code{set-fontset-font} function.
@cindex script of a character
@cindex codepoint of a character
If you don't know the character's codepoint or the script to which it
belongs, you can ask Emacs. With point at the character, type
@w{@kbd{C-u C-x =}} (@code{what-cursor-position}), and this
information, together with much more, will be displayed in the
@file{*Help*} buffer that Emacs pops up. @xref{Position Info}. For
example, Japanese characters belong to the @samp{kana} script, but
Japanese text also mixes them with Chinese characters so the following
uses the @samp{han} script to set up Emacs to use the @samp{Kochi
Gothic} font for Japanese text:
@example
(set-fontset-font "fontset-default" 'han "Kochi Gothic")
@end example
@noindent
@cindex CKJ characters
(For convenience, the @samp{han} script in Emacs is set up to support
all of the Chinese, Japanese, and Korean, a.k.a.@: @acronym{CJK},
characters, not just Chinese characters.)
@vindex script-representative-chars
For the list of known scripts, see the variable
@code{script-representative-chars}.
Fontset settings like those above only affect characters that the
default font doesn't support, so if the @samp{Kochi Gothic} font
covers Latin characters, it will not be used for displaying Latin
scripts, since the default font used by Emacs usually covers Basic
Latin.
@cindex ignore font
@cindex fonts, how to ignore
@vindex face-ignored-fonts

View file

@ -7317,8 +7317,6 @@ which leave the original list as it was. One way to find out how this
works is to experiment. We will start with the @code{setcar} function.
@need 1200
@cindex constant lists
@cindex mutable lists
First, we can make a list and then set the value of a variable to the
list, using the @code{setq} special form. Because we intend to use
@code{setcar} to change the list, this @code{setq} should not use the
@ -7327,8 +7325,7 @@ a list that is part of the program and bad things could happen if we
tried to change part of the program while running it. Generally
speaking an Emacs Lisp program's components should be constant (or
unchanged) while the program is running. So we instead construct an
animal list that is @dfn{mutable} (or changeable) by using the
@code{list} function, as follows:
animal list by using the @code{list} function, as follows:
@smallexample
(setq animals (list 'antelope 'giraffe 'lion 'tiger))

View file

@ -1905,6 +1905,7 @@ variables precisely as they were at the time of the error.
@subsubsection Writing Code to Handle Errors
@cindex error handler
@cindex handling errors
@cindex handle Lisp errors
@cindex forms for handling errors
The usual effect of signaling an error is to terminate the command

View file

@ -3597,9 +3597,9 @@ characters in the range @var{from} and @var{to} (inclusive).
@var{character} may be a charset (@pxref{Character Sets}). In that
case, use @var{font-spec} for all the characters in the charset.
@var{character} may be a script name (@pxref{Character Properties}).
In that case, use @var{font-spec} for all the characters belonging to
the script.
@var{character} may be a script name (@pxref{Character Properties,
char-script-table}). In that case, use @var{font-spec} for all the
characters belonging to the script.
@var{character} may be @code{nil}, which means to use @var{font-spec}
for any character which no font-spec is specified.

View file

@ -297,7 +297,7 @@ Lisp Data Types
* Circular Objects:: Read syntax for circular structure.
* Type Predicates:: Tests related to types.
* Equality Predicates:: Tests of equality between any two objects.
* Constants and Mutability:: Whether an object's value can change.
* Mutability:: Some objects should not be modified.
Programming Types

View file

@ -158,11 +158,11 @@ contents unchanged.
@end group
@end example
A self-evaluating form yields constant conses, vectors and strings, and you
should not attempt to modify their contents via @code{setcar}, @code{aset} or
A self-evaluating form yields a value that becomes part of the program,
and you should not try to modify it via @code{setcar}, @code{aset} or
similar operations. The Lisp interpreter might unify the constants
yielded by your program's self-evaluating forms, so that these
constants might share structure. @xref{Constants and Mutability}.
constants might share structure. @xref{Mutability}.
It is common to write numbers, characters, strings, and even vectors
in Lisp code, taking advantage of the fact that they self-evaluate.
@ -564,8 +564,8 @@ and vectors.)
@defspec quote object
This special form returns @var{object}, without evaluating it.
The returned value is a constant, and should not be modified.
@xref{Constants and Mutability}.
The returned value might be shared and should not be modified.
@xref{Self-Evaluating Forms}.
@end defspec
@cindex @samp{'} for quoting
@ -608,9 +608,9 @@ Here are some examples of expressions that use @code{quote}:
Although the expressions @code{(list '+ 1 2)} and @code{'(+ 1 2)}
both yield lists equal to @code{(+ 1 2)}, the former yields a
freshly-minted mutable list whereas the latter yields a constant list
built from conses that may be shared with other constants.
@xref{Constants and Mutability}.
freshly-minted mutable list whereas the latter yields a list
built from conses that might be shared and should not be modified.
@xref{Self-Evaluating Forms}.
Other quoting constructs include @code{function} (@pxref{Anonymous
Functions}), which causes an anonymous lambda expression written in Lisp
@ -710,8 +710,9 @@ Here are some examples:
@end example
If a subexpression of a backquote construct has no substitutions or
splices, it acts like @code{quote} in that it yields constant conses,
vectors and strings that should not be modified.
splices, it acts like @code{quote} in that it yields conses,
vectors and strings that might be shared and should not be modified.
@xref{Self-Evaluating Forms}.
@node Eval
@section Eval

View file

@ -873,8 +873,8 @@ primitives @code{setcar} and @code{setcdr}. These are destructive
operations because they change existing list structure.
Destructive operations should be applied only to mutable lists,
that is, lists constructed via @code{cons}, @code{list} or similar
operations. Lists created by quoting are constants and should not be
changed by destructive operations. @xref{Constants and Mutability}.
operations. Lists created by quoting are part of the program and
should not be changed by destructive operations. @xref{Mutability}.
@cindex CL note---@code{rplaca} vs @code{setcar}
@quotation
@ -911,7 +911,7 @@ value @var{object}. For example:
@example
@group
(setq x (list 1 2)) ; @r{Create a mutable list.}
(setq x (list 1 2))
@result{} (1 2)
@end group
@group
@ -931,7 +931,7 @@ these lists. Here is an example:
@example
@group
;; @r{Create two mutable lists that are partly shared.}
;; @r{Create two lists that are partly shared.}
(setq x1 (list 'a 'b 'c))
@result{} (a b c)
(setq x2 (cons 'z (cdr x1)))
@ -1022,11 +1022,11 @@ reached via the @sc{cdr}.
@example
@group
(setq x (list 1 2 3)) ; @r{Create a mutable list.}
(setq x (list 1 2 3))
@result{} (1 2 3)
@end group
@group
(setcdr x '(4)) ; @r{Modify the list's tail to be a constant list.}
(setcdr x '(4))
@result{} (4)
@end group
@group
@ -1135,11 +1135,11 @@ Unlike @code{append} (@pxref{Building Lists}), the @var{lists} are
@example
@group
(setq x (list 1 2 3)) ; @r{Create a mutable list.}
(setq x (list 1 2 3))
@result{} (1 2 3)
@end group
@group
(nconc x '(4 5)) ; @r{Modify the list's tail to be a constant list.}
(nconc x '(4 5))
@result{} (1 2 3 4 5)
@end group
@group

View file

@ -46,10 +46,6 @@ you store in it, type and all. (Actually, a small number of Emacs
Lisp variables can only take on values of a certain type.
@xref{Variables with Restricted Values}.)
Some Lisp objects are @dfn{constant}: their values should never change.
Others are @dfn{mutable}: their values can be changed via destructive
operations that involve side effects.
This chapter describes the purpose, printed representation, and read
syntax of each of the standard types in GNU Emacs Lisp. Details on how
to use these types can be found in later chapters.
@ -63,7 +59,7 @@ to use these types can be found in later chapters.
* Circular Objects:: Read syntax for circular structure.
* Type Predicates:: Tests related to types.
* Equality Predicates:: Tests of equality between any two objects.
* Constants and Mutability:: Whether an object's value can change.
* Mutability:: Some objects should not be modified.
@end menu
@node Printed Representation
@ -2383,51 +2379,58 @@ that for two strings to be equal, they have the same text properties.
@end example
@end defun
@node Constants and Mutability
@section Constants and Mutability
@cindex constants
@node Mutability
@section Mutability
@cindex mutable objects
Some Lisp objects are constant: their values should never change
during a single execution of Emacs running well-behaved Lisp code.
For example, you can create a new integer by calculating one, but you
cannot modify the value of an existing integer.
Some Lisp objects should never change. For example, the Lisp
expression @code{"aaa"} yields a string, but you should not change
its contents. And some objects cannot be changed; for example,
although you can create a new number by calculating one, Lisp provides
no operation to change the value of an existing number.
Other Lisp objects are mutable: it is safe to change their values
via destructive operations involving side effects. For example, an
existing marker can be changed by moving the marker to point to
somewhere else.
Other Lisp objects are @dfn{mutable}: it is safe to change their
values via destructive operations involving side effects. For
example, an existing marker can be changed by moving the marker to
point to somewhere else.
Although all numbers are constants and all markers are
mutable, some types contain both constant and mutable members. These
types include conses, vectors, strings, and symbols. For example, the string
literal @code{"aaa"} yields a constant string, whereas the function
call @code{(make-string 3 ?a)} yields a mutable string that can be
Although numbers never change and all markers are mutable,
some types have members some of which are mutable and others not. These
types include conses, vectors, and strings. For example,
although @code{"cons"} and @code{(symbol-name 'cons)} both yield
strings that should not be changed, @code{(copy-sequence "cons")} and
@code{(make-string 3 ?a)} both yield mutable strings that can be
changed via later calls to @code{aset}.
A mutable object can become constant if it is part of an expression
that is evaluated. The reverse does not occur: constant objects
should stay constant.
A mutable object stops being mutable if it is part of an expression
that is evaluated. For example:
Trying to modify a constant variable signals an error
(@pxref{Constant Variables}).
A program should not attempt to modify other types of constants because the
resulting behavior is undefined: the Lisp interpreter might or might
not detect the error, and if it does not detect the error the
interpreter can behave unpredictably thereafter. Another way to put
this is that although mutable objects are safe to change and constant
variables reliably prevent attempts to change them, other constants
are not safely mutable: if a misbehaving program tries to change such a
constant then the constant's value might actually change, or the
program might crash or worse. This problem occurs
with types that have both constant and mutable members, and that have
mutators like @code{setcar} and @code{aset} that are valid on mutable
objects but hazardous on constants.
@example
(let* ((x (list 0.5))
(y (eval (list 'quote x))))
(setcar x 1.5) ;; The program should not do this.
y)
@end example
When the same constant occurs multiple times in a program, the Lisp
@noindent
Although the list @code{(0.5)} was mutable when it was created, it should not
have been changed via @code{setcar} because it given to @code{eval}. The
reverse does not occur: an object that should not be changed never
becomes mutable afterwards.
If a program attempts to change objects that should not be
changed, the resulting behavior is undefined: the Lisp interpreter
might signal an error, or it might crash or behave unpredictably in
other ways.@footnote{This is the behavior specified for languages like
Common Lisp and C for constants, and this differs from languages like
JavaScript and Python where an interpreter is required to signal an
error if a program attempts to change an immutable object. Ideally the Emacs
Lisp interpreter will evolve in latter direction.}
When similar constants occur as parts of a program, the Lisp
interpreter might save time or space by reusing existing constants or
constant components. For example, @code{(eq "abc" "abc")} returns
their components. For example, @code{(eq "abc" "abc")} returns
@code{t} if the interpreter creates only one instance of the string
constant @code{"abc"}, and returns @code{nil} if it creates two
literal @code{"abc"}, and returns @code{nil} if it creates two
instances. Lisp programs should be written so that they work
regardless of whether this optimization is in use.

View file

@ -183,11 +183,11 @@ for other ways to copy sequences.
@example
@group
(setq bar (list 1 2)) ; @r{Create a mutable list.}
(setq bar (list 1 2))
@result{} (1 2)
@end group
@group
(setq x (vector 'foo bar)) ; @r{Create a mutable vector.}
(setq x (vector 'foo bar))
@result{} [foo (1 2)]
@end group
@group
@ -278,7 +278,7 @@ Unlike @code{reverse} the original @var{sequence} may be modified.
@example
@group
(setq x (list 'a 'b 'c)) ; @r{Create a mutable list.}
(setq x (list 'a 'b 'c))
@result{} (a b c)
@end group
@group
@ -320,7 +320,7 @@ presented graphically:
For the vector, it is even simpler because you don't need setq:
@example
(setq x (copy-sequence [1 2 3 4])) ; @r{Create a mutable vector.}
(setq x (copy-sequence [1 2 3 4]))
@result{} [1 2 3 4]
(nreverse x)
@result{} [4 3 2 1]
@ -331,6 +331,7 @@ x
Note that unlike @code{reverse}, this function doesn't work with strings.
Although you can alter string data by using @code{aset}, it is strongly
encouraged to treat strings as immutable even when they are mutable.
@xref{Mutability}.
@end defun
@ -374,7 +375,7 @@ appears in a different position in the list due to the change of
@example
@group
(setq nums (list 1 3 2 6 5 4 0)) ; @r{Create a mutable list.}
(setq nums (list 1 3 2 6 5 4 0))
@result{} (1 3 2 6 5 4 0)
@end group
@group
@ -1228,7 +1229,7 @@ This function sets the @var{index}th element of @var{array} to be
@example
@group
(setq w (vector 'foo 'bar 'baz)) ; @r{Create a mutable vector.}
(setq w (vector 'foo 'bar 'baz))
@result{} [foo bar baz]
(aset w 0 'fu)
@result{} fu
@ -1237,7 +1238,7 @@ w
@end group
@group
;; @r{@code{copy-sequence} creates a mutable string.}
;; @r{@code{copy-sequence} copies the string to be modified later.}
(setq x (copy-sequence "asdfasfd"))
@result{} "asdfasfd"
(aset x 3 ?Z)
@ -1247,9 +1248,7 @@ x
@end group
@end example
The @var{array} should be mutable; that is, it should not be a constant,
such as the constants created via quoting or via self-evaluating forms.
@xref{Constants and Mutability}.
The @var{array} should be mutable. @xref{Mutability}.
If @var{array} is a string and @var{object} is not a character, a
@code{wrong-type-argument} error results. The function converts a
@ -1262,7 +1261,6 @@ each element of @var{array} is @var{object}. It returns @var{array}.
@example
@group
;; @r{Create a mutable vector and then fill it with zeros.}
(setq a (copy-sequence [a b c d e f g]))
@result{} [a b c d e f g]
(fillarray a 0)
@ -1271,7 +1269,6 @@ a
@result{} [0 0 0 0 0 0 0]
@end group
@group
;; @r{Create a mutable string and then fill it with "-".}
(setq s (copy-sequence "When in the course"))
@result{} "When in the course"
(fillarray s ?-)
@ -1310,8 +1307,8 @@ same way in Lisp input.
evaluation: the result of evaluating it is the same vector. This does
not evaluate or even examine the elements of the vector.
@xref{Self-Evaluating Forms}. Vectors written with square brackets
are constants and should not be modified via @code{aset} or other
destructive operations. @xref{Constants and Mutability}.
should not be modified via @code{aset} or other destructive
operations. @xref{Mutability}.
Here are examples illustrating these principles:

View file

@ -49,10 +49,9 @@ by a distinguished character code.
Since strings are arrays, and therefore sequences as well, you can
operate on them with the general array and sequence functions documented
in @ref{Sequences Arrays Vectors}. For example, you can access or
change individual characters in a string using the functions @code{aref}
and @code{aset} (@pxref{Array Functions}). However, you should not
try to change the contents of constant strings (@pxref{Modifying Strings}).
in @ref{Sequences Arrays Vectors}. For example, you can access
individual characters in a string using the function @code{aref}
(@pxref{Array Functions}).
There are two text representations for non-@acronym{ASCII}
characters in Emacs strings (and in buffers): unibyte and multibyte.
@ -382,9 +381,7 @@ usual value is @w{@code{"[ \f\t\n\r\v]+"}}.
@cindex string modification
You can alter the contents of a mutable string via operations
described in this section. However, you should not try to use these
operations to alter the contents of a constant string.
@xref{Constants and Mutability}.
described in this section. @xref{Mutability}.
The most basic way to alter the contents of an existing string is with
@code{aset} (@pxref{Array Functions}). @code{(aset @var{string}

View file

@ -139,6 +139,9 @@ directories with the help of new command 'dired-vc-next-action'.
*** New commands 'vc-dir-mark-registered-files' (bound to '* r') and
'vc-dir-mark-unregistered-files'.
*** Support for bookmark.el.
Bookmark locations can refer to VC directory buffers.
** Gnus
---
@ -226,6 +229,12 @@ key binding
/ m package-menu-filter-marked
/ / package-menu-filter-clear
---
+++ Column widths in 'list-packages' display can now be customized.
See the new user options 'package-name-column-width',
'package-version-column-width', 'package-status-column-width', and
'package-archive-column-width'.
** gdb-mi
+++
@ -353,6 +362,44 @@ symbol property to the browsing functions. With a new command
'browse-url-with-browser-kind', an URL can explicitly be browsed with
either an internal or external browser.
** SHR
---
*** The command 'shr-browse-url' now supports custom mailto handlers.
Clicking on or otherwise following a 'mailto:' link in a HTML buffer
rendered by SHR previously invoked the command 'browse-url-mailto'.
This is still the case by default, but if you customize
'browse-url-mailto-function' or 'browse-url-handlers' to call some
other function, it will now be called instead of the default.
** EWW
---
*** The command 'eww-follow-link' now supports custom mailto handlers.
The function that is invoked when clicking on or otherwise following a
'mailto:' link in an EWW buffer can now be customized. For more
information, see the related entry about 'shr-browse-url' above.
** Project
*** New user option 'project-vc-merge-submodules'.
** json.el
---
*** JSON number parsing is now stricter.
Numbers with a leading plus sign, leading zeros, or a missing integer
component are now rejected by 'json-read' and friends. This makes
them more compliant with the JSON specification and consistent with
the native JSON parsing functions.
** xml.el
*** XML serialization functions now reject invalid characters.
Previously 'xml-print' would produce invalid XML when given a string
with characters that are not valid in XML (see
https://www.w3.org/TR/xml/#charsets). Now it rejects such strings.
* New Modes and Packages in Emacs 28.1

View file

@ -220,10 +220,23 @@ https://lists.gnu.org/r/emacs-devel/2013-11/msg00515.html
width fonts. However, more features are still needed to achieve this.
** Support ligatures out of the box
For the list of typographical ligatures, see
For the list of frequently-used typographical ligatures, see
https://en.wikipedia.org/wiki/Orthographic_ligature#Ligatures_in_Unicode_(Latin_alphabets)
(Note that in general, the number of possible ligatures can be much
larger, and there's no way, in principle, to specify the superset of
all the ligatures that could exist. Each font can support different
ligatures. The reliable way of supporting any and all ligatures is to
hand all text to be displayed to the shaping engine and get back the
font glyphs to display that text. However, doing this is impossible
with the current design of the Emacs display engine, since it examines
buffer text one character at a time, and implements character
composition by calls to Lisp, which makes doing this for every
character impractically slow. Therefore, the rest of this item
describes a limited form of ligature support which is compatible with
the current display engine design and uses automatic compositions.)
For Text and derived modes, the job is to figure out which ligatures
we want to support, how to let the user customize that, and probably
define a minor mode for automatic ligation (as some contexts might not
@ -237,12 +250,12 @@ prettify-symbols-mode. We need to figure out which ligatures are
needed for each programming language, and provide user options to turn
this on and off.
The implementation should use the infrastructure for character
compositions, i.e., we should define appropriate regexp-based rules
for character sequences that need to be composed into ligatures, and
populate composition-function-table with those rules. See
composite.el for examples of this, and also grep lisp/language/*.el
for references to composition-function-table.
The implementation should use the infrastructure for automatic
character compositions, i.e., we should define appropriate
regexp-based rules for character sequences that need to be composed
into ligatures, and populate composition-function-table with those
rules. See composite.el for examples of this, and also grep
lisp/language/*.el for references to composition-function-table.
One problem with character compositions that will need to be solved is
that composition-function-table, the char-table which holds the
@ -259,11 +272,46 @@ way of preventing the ligation from happening. One possibility is to
have a ZWNJ character separate these ASCII characters; another
possibility is to introduce a special text property that prevents
character composition, and place that property on the relevant parts
of the mode line.
of the mode line. Yet another possibility would be to write a
specialized composition function, which would detect that it is called
on mode-line strings, and return nil to signal that composition is not
possible in this case; then use that function in the rules for
ligatures stored in composition-function-table.
The prettify-symbols-mode should be deprecated once ligature support
is in place.
A related, but somewhat independent, feature is being able to move the
cursor "into a ligature", whereby cursor motion commands shows some
pseudo-cursor on some part of a ligature. For example, if "ffi" is
displayed as a ligature, then moving by one buffer position should
show the middle part of the ligature's glyph similar to the cursor
display: some special background and perhaps also a special
foreground. There are two possible ways of figuring out the offset at
which to display the pseudo-cursor:
. Arbitrarily divide the ligature's glyph width W into N parts,
where N is the number of codepoints composed into the ligature, then
move that pseudo-cursor by W/N pixels each time a cursor-motion
command is invoked;
. Use the font information. For example, HarfBuzz has the
hb_ot_layout_get_ligature_carets API for that purpose. However,
it could be that few fonts actually have that information recorded
in them, in which case the previous heuristics will be needed as
fallback.
One subtle issue needs to be resolved to have this feature of
"sub-glyph" cursor movement inside composed characters. The way Emacs
currently displays the default block cursor is by simply redrawing the
glyph at point in reverse video. So Emacs currently doesn't have a
way of displaying a cursor that "covers" only part of a glyph. To
make this happen, the display code will probably need to be changed to
draw the cursor as part of drawing the foreground and/or background of
the corresponding glyph, which is against the current flow of the
display code: it generally first completely draws the background and
foreground of the entire text that needs to be redrawn, and only then
draws the cursor where it should be placed.
** Support for Stylistic Sets
This will allow using "alternate glyphs" supported by modern fonts.
For an overview of this feature, see

View file

@ -4197,9 +4197,9 @@ C_entries (int c_ext, FILE *inf)
break;
}
FALLTHROUGH;
resetfvdef:
case '#': case '~': case '&': case '%': case '/':
case '|': case '^': case '!': case '.': case '?':
resetfvdef:
if (definedef != dnone)
break;
/* These surely cannot follow a function tag in C. */

View file

@ -858,12 +858,10 @@ The result should not exceed the screen width."
"Convert the given STR to a number, according to the value of
`calculator-input-radix'."
(if calculator-input-radix
(string-to-number str (cadr (assq calculator-input-radix
'((bin 2) (oct 8) (hex 16)))))
(let* ((str (replace-regexp-in-string
"\\.\\([^0-9].*\\)?$" ".0\\1" str))
(str (replace-regexp-in-string
"[eE][+-]?\\([^0-9].*\\)?$" "e0\\1" str)))
(string-to-number str (cadr (assq calculator-input-radix
'((bin 2) (oct 8) (hex 16)))))
;; Allow entry of "1.e3".
(let ((str (replace-regexp-in-string (rx "." (any "eE")) "e" str)))
(float (string-to-number str)))))
(defun calculator-push-curnum ()

View file

@ -1515,8 +1515,11 @@ It does not apply the value to buffers."
(when project-dir
(ede-directory-get-open-project project-dir 'ROOT))))
(cl-defmethod project-roots ((project ede-project))
(list (ede-project-root-directory project)))
(cl-defmethod project-root ((project ede-project))
(ede-project-root-directory project))
;;; FIXME: Could someone look into implementing `project-ignores' for
;;; EDE and/or a faster `project-files'?
(add-hook 'project-find-functions #'project-try-ede)

View file

@ -2050,8 +2050,8 @@ See the command `doc-view-mode' for more information on this mode."
(when (memq (selected-frame) (alist-get 'frames attrs))
(let ((geom (alist-get 'geometry attrs)))
(when geom
(setq monitor-top (nth 0 geom))
(setq monitor-left (nth 1 geom))
(setq monitor-left (nth 0 geom))
(setq monitor-top (nth 1 geom))
(setq monitor-width (nth 2 geom))
(setq monitor-height (nth 3 geom))))))
(let ((frame (make-frame

View file

@ -397,6 +397,26 @@ synchronously."
:type 'boolean
:version "25.1")
(defcustom package-name-column-width 30
"Column width for the Package name in the package menu."
:type 'number
:version "28.1")
(defcustom package-version-column-width 14
"Column width for the Package version in the package menu."
:type 'number
:version "28.1")
(defcustom package-status-column-width 12
"Column width for the Package status in the package menu."
:type 'number
:version "28.1")
(defcustom package-archive-column-width 8
"Column width for the Package status in the package menu."
:type 'number
:version "28.1")
;;; `package-desc' object definition
;; This is the struct used internally to represent packages.
@ -2750,11 +2770,11 @@ Letters do not insert themselves; instead, they are commands.
(package-menu--transaction-status
package-menu--transaction-status)))
(setq tabulated-list-format
`[("Package" 18 package-menu--name-predicate)
("Version" 13 package-menu--version-predicate)
("Status" 10 package-menu--status-predicate)
`[("Package" ,package-name-column-width package-menu--name-predicate)
("Version" ,package-version-column-width package-menu--version-predicate)
("Status" ,package-status-column-width package-menu--status-predicate)
,@(if (cdr package-archives)
'(("Archive" 10 package-menu--archive-predicate)))
`(("Archive" ,package-archive-column-width package-menu--archive-predicate)))
("Description" 0 package-menu--description-predicate)])
(setq tabulated-list-padding 2)
(setq tabulated-list-sort-key (cons "Status" nil))

View file

@ -139,14 +139,28 @@ delimiter or an Escaped or Char-quoted character."))
(point-max))))
(cons beg end))
(defun syntax-propertize--shift-groups (re n)
(replace-regexp-in-string
"\\\\(\\?\\([0-9]+\\):"
(lambda (s)
(replace-match
(number-to-string (+ n (string-to-number (match-string 1 s))))
t t s 1))
re t t))
(defun syntax-propertize--shift-groups-and-backrefs (re n)
(let ((new-re (replace-regexp-in-string
"\\\\(\\?\\([0-9]+\\):"
(lambda (s)
(replace-match
(number-to-string
(+ n (string-to-number (match-string 1 s))))
t t s 1))
re t t))
(pos 0))
(while (string-match "\\\\\\([0-9]+\\)" new-re pos)
(setq pos (+ 1 (match-beginning 1)))
(when (save-match-data
;; With \N, the \ must be in a subregexp context, i.e.,
;; not in a character class or in a \{\} repetition.
(subregexp-context-p new-re (match-beginning 0)))
(let ((shifted (+ n (string-to-number (match-string 1 new-re)))))
(when (> shifted 9)
(error "There may be at most nine back-references"))
(setq new-re (replace-match (number-to-string shifted)
t t new-re 1)))))
new-re))
(defmacro syntax-propertize-precompile-rules (&rest rules)
"Return a precompiled form of RULES to pass to `syntax-propertize-rules'.
@ -190,7 +204,8 @@ for subsequent HIGHLIGHTs.
Also SYNTAX is free to move point, in which case RULES may not be applied to
some parts of the text or may be applied several times to other parts.
Note: back-references in REGEXPs do not work."
Note: There may be at most nine back-references in the REGEXPs of
all RULES in total."
(declare (debug (&rest &or symbolp ;FIXME: edebug this eval step.
(form &rest
(numberp
@ -219,7 +234,7 @@ Note: back-references in REGEXPs do not work."
;; tell when *this* match 0 has succeeded.
(cl-incf offset)
(setq re (concat "\\(" re "\\)")))
(setq re (syntax-propertize--shift-groups re offset))
(setq re (syntax-propertize--shift-groups-and-backrefs re offset))
(let ((code '())
(condition
(cond

View file

@ -5833,6 +5833,7 @@ all parts."
"" "..."))
(gnus-tmp-length (with-current-buffer (mm-handle-buffer handle)
(buffer-size)))
(help-echo "mouse-2: toggle the MIME part; down-mouse-3: more options")
gnus-tmp-type-long b e)
(when (string-match ".*/" gnus-tmp-name)
(setq gnus-tmp-name (replace-match "" t t gnus-tmp-name)))
@ -5841,6 +5842,16 @@ all parts."
(concat "; " gnus-tmp-name))))
(unless (equal gnus-tmp-description "")
(setq gnus-tmp-type-long (concat " --- " gnus-tmp-type-long)))
(when (zerop gnus-tmp-length)
(setq gnus-tmp-type-long
(concat
gnus-tmp-type-long
(substitute-command-keys
(concat "\\<gnus-summary-mode-map> (not downloaded, "
"\\[gnus-summary-show-complete-article] to fetch.)"))))
(setq help-echo
(concat "Type \\[gnus-summary-show-complete-article] "
"to download complete article. " help-echo)))
(setq b (point))
(gnus-eval-format
gnus-mime-button-line-format gnus-mime-button-line-format-alist
@ -5859,8 +5870,7 @@ all parts."
'keymap gnus-mime-button-map
'face gnus-article-button-face
'follow-link t
'help-echo
"mouse-2: toggle the MIME part; down-mouse-3: more options")))
'help-echo help-echo)))
(defvar gnus-displaying-mime nil)

View file

@ -485,23 +485,25 @@ This is not required after changing `gnus-registry-cache-file'."
(when from
(setq entry (cons (delete from (assoc 'group entry))
(assq-delete-all 'group entry))))
(dolist (kv `((group ,to)
(sender ,sender)
(recipient ,@recipients)
(subject ,subject)))
(when (cadr kv)
(let ((new (or (assq (car kv) entry)
(list (car kv)))))
(dolist (toadd (cdr kv))
(unless (member toadd new)
(setq new (append new (list toadd)))))
(setq entry (cons new
(assq-delete-all (car kv) entry))))))
(gnus-message 10 "Gnus registry: new entry for %s is %S"
id
entry)
(gnus-registry-insert db id entry)))
;; Only keep the entry if the message is going to a new group, or
;; it's still in some previous group.
(when (or to (alist-get 'group entry))
(dolist (kv `((group ,to)
(sender ,sender)
(recipient ,@recipients)
(subject ,subject)))
(when (cadr kv)
(let ((new (or (assq (car kv) entry)
(list (car kv)))))
(dolist (toadd (cdr kv))
(unless (member toadd new)
(setq new (append new (list toadd)))))
(setq entry (cons new
(assq-delete-all (car kv) entry))))))
(gnus-message 10 "Gnus registry: new entry for %s is %S"
id
entry)
(gnus-registry-insert db id entry))))
;; Function for nn{mail|imap}-split-fancy: look up all references in
;; the cache and if a match is found, return that group.

View file

@ -499,11 +499,14 @@ This means that \\[ido-complete] must always be followed by \\[ido-exit-minibuff
even when there is only one unique completion."
:type 'boolean)
(defcustom ido-cannot-complete-command 'ido-completion-help
(defcustom ido-cannot-complete-command #'ido-completion-auto-help
"Command run when `ido-complete' can't complete any more.
The most useful values are `ido-completion-help', which pops up a
window with completion alternatives, or `ido-next-match' or
`ido-prev-match', which cycle the buffer list."
window with completion alternatives; `ido-completion-auto-help',
which does the same but respects the value of
`completion-auto-help'; and `ido-next-match' or `ido-prev-match',
which cycle the buffer list."
:version "28.1"
:type 'function)
@ -1546,7 +1549,7 @@ This function also adds a hook to the minibuffer."
((> (prefix-numeric-value arg) 0) 'both)
(t nil)))
(ido-everywhere (if ido-everywhere 1 -1))
(ido-everywhere (if (and ido-mode ido-everywhere) 1 -1))
(when ido-mode
(ido-common-initialization)
@ -3926,6 +3929,14 @@ If `ido-change-word-sub' cannot be found in WORD, return nil."
(when (bobp)
(next-completion 1)))))
(defun ido-completion-auto-help ()
"Call `ido-completion-help' if `completion-auto-help' is non-nil."
(interactive)
;; Note: `completion-auto-help' could also be `lazy', but this value
;; is irrelevant to ido, which is fundamentally eager, so it is
;; treated the same as t.
(when completion-auto-help
(ido-completion-help)))
(defun ido-completion-help ()
"Show possible completions in the `ido-completion-buffer'."

View file

@ -3,7 +3,7 @@
;; Copyright (C) 2006-2020 Free Software Foundation, Inc.
;; Author: Theresa O'Connor <ted@oconnor.cx>
;; Version: 1.4
;; Version: 1.5
;; Keywords: convenience
;; This file is part of GNU Emacs.
@ -29,11 +29,11 @@
;; Learn all about JSON here: <URL:http://json.org/>.
;; The user-serviceable entry points for the parser are the functions
;; `json-read' and `json-read-from-string'. The encoder has a single
;; `json-read' and `json-read-from-string'. The encoder has a single
;; entry point, `json-encode'.
;; Since there are several natural representations of key-value pair
;; mappings in elisp (alist, plist, hash-table), `json-read' allows you
;; mappings in Elisp (alist, plist, hash-table), `json-read' allows you
;; to specify which you'd prefer (see `json-object-type' and
;; `json-array-type').
@ -55,6 +55,7 @@
;;; Code:
(require 'map)
(require 'seq)
(require 'subr-x)
;; Parameters
@ -113,8 +114,10 @@ Used only when `json-encoding-pretty-print' is non-nil.")
"If non-nil, then the output of `json-encode' will be pretty-printed.")
(defvar json-encoding-lisp-style-closings nil
"If non-nil, ] and } closings will be formatted lisp-style,
without indentation.")
"If non-nil, delimiters ] and } will be formatted Lisp-style.
This means they will be placed on the same line as the last
element of the respective array or object, without indentation.
Used only when `json-encoding-pretty-print' is non-nil.")
(defvar json-encoding-object-sort-predicate nil
"Sorting predicate for JSON object keys during encoding.
@ -124,88 +127,81 @@ instance, setting this to `string<' will have JSON object keys
ordered alphabetically.")
(defvar json-pre-element-read-function nil
"Function called (if non-nil) by `json-read-array' and
`json-read-object' right before reading a JSON array or object,
respectively. The function is called with one argument, which is
the current JSON key.")
"If non-nil, a function to call before reading a JSON array or object.
It is called by `json-read-array' and `json-read-object',
respectively, with one argument, which is the current JSON key.")
(defvar json-post-element-read-function nil
"Function called (if non-nil) by `json-read-array' and
`json-read-object' right after reading a JSON array or object,
respectively.")
"If non-nil, a function to call after reading a JSON array or object.
It is called by `json-read-array' and `json-read-object',
respectively, with no arguments.")
;;; Utilities
(defun json-join (strings separator)
"Join STRINGS with SEPARATOR."
(mapconcat 'identity strings separator))
(define-obsolete-function-alias 'json-join #'string-join "28.1")
(defun json-alist-p (list)
"Non-null if and only if LIST is an alist with simple keys."
(while (consp list)
(setq list (if (and (consp (car list))
(atom (caar list)))
(cdr list)
'not-alist)))
"Non-nil if and only if LIST is an alist with simple keys."
(declare (pure t) (side-effect-free error-free))
(while (and (consp (car-safe list))
(atom (caar list))
(setq list (cdr list))))
(null list))
(defun json-plist-p (list)
"Non-null if and only if LIST is a plist with keyword keys."
(while (consp list)
(setq list (if (and (keywordp (car list))
(consp (cdr list)))
(cddr list)
'not-plist)))
"Non-nil if and only if LIST is a plist with keyword keys."
(declare (pure t) (side-effect-free error-free))
(while (and (keywordp (car-safe list))
(consp (cdr list))
(setq list (cddr list))))
(null list))
(defun json--plist-reverse (plist)
"Return a copy of PLIST in reverse order.
Unlike `reverse', this keeps the property-value pairs intact."
(let (res)
(while plist
(let ((prop (pop plist))
(val (pop plist)))
(push val res)
(push prop res)))
res))
(defun json--plist-nreverse (plist)
"Return PLIST in reverse order.
Unlike `nreverse', this keeps the ordering of each property
relative to its value intact. Like `nreverse', this function may
destructively modify PLIST to produce the result."
(let (prev (next (cddr plist)))
(while next
(setcdr (cdr plist) prev)
(setq prev plist plist next next (cddr next))
(setcdr (cdr plist) prev)))
plist)
(defun json--plist-to-alist (plist)
"Return an alist of the property-value pairs in PLIST."
(let (res)
(while plist
(let ((prop (pop plist))
(val (pop plist)))
(push (cons prop val) res)))
(nreverse res)))
(defmacro json--with-indentation (body)
(defmacro json--with-indentation (&rest body)
"Evaluate BODY with the correct indentation for JSON encoding.
This macro binds `json--encoding-current-indentation' according
to `json-encoding-pretty-print' around BODY."
(declare (debug t) (indent 0))
`(let ((json--encoding-current-indentation
(if json-encoding-pretty-print
(concat json--encoding-current-indentation
json-encoding-default-indentation)
"")))
,body))
,@body))
;; Reader utilities
(define-inline json-advance (&optional n)
"Advance N characters forward."
"Advance N characters forward, or 1 character if N is nil.
On reaching the end of the accessible region of the buffer, stop
and signal an error."
(inline-quote (forward-char ,n)))
(define-inline json-peek ()
"Return the character at point."
"Return the character at point.
At the end of the accessible region of the buffer, return 0."
(inline-quote (following-char)))
(define-inline json-pop ()
"Advance past the character at point, returning it."
"Advance past the character at point, returning it.
Signal `json-end-of-file' if called at the end of the buffer."
(inline-quote
(let ((char (json-peek)))
(if (zerop char)
(signal 'json-end-of-file nil)
(json-advance)
char))))
(prog1 (or (char-after)
(signal 'json-end-of-file ()))
(json-advance))))
(define-inline json-skip-whitespace ()
"Skip past the whitespace at point."
@ -213,7 +209,7 @@ Unlike `reverse', this keeps the property-value pairs intact."
;; https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
;; or https://tools.ietf.org/html/rfc7159#section-2 for the
;; definition of whitespace in JSON.
(inline-quote (skip-chars-forward "\t\r\n ")))
(inline-quote (skip-chars-forward "\t\n\r ")))
@ -236,8 +232,8 @@ Unlike `reverse', this keeps the property-value pairs intact."
;;; Paths
(defvar json--path '()
"Used internally by `json-path-to-position' to keep track of
the path during recursive calls to `json-read'.")
"Keeps track of the path during recursive calls to `json-read'.
Used internally by `json-path-to-position'.")
(defun json--record-path (key)
"Record the KEY to the current JSON path.
@ -248,7 +244,7 @@ Used internally by `json-path-to-position'."
"Check if the last parsed JSON structure passed POSITION.
Used internally by `json-path-to-position'."
(let ((start (caar json--path)))
(when (< start position (+ (point) 1))
(when (< start position (1+ (point)))
(throw :json-path (list :path (nreverse (mapcar #'cdr json--path))
:match-start start
:match-end (point)))))
@ -266,13 +262,13 @@ properties:
:path -- A list of strings and numbers forming the path to
the JSON element at the given position. Strings
denote object names, while numbers denote array
indexes.
indices.
:match-start -- Position where the matched JSON element begins.
:match-end -- Position where the matched JSON element ends.
This can for instance be useful to determine the path to a JSON
This can, for instance, be useful to determine the path to a JSON
element in a deeply nested structure."
(save-excursion
(unless string
@ -280,7 +276,7 @@ element in a deeply nested structure."
(let* ((json--path '())
(json-pre-element-read-function #'json--record-path)
(json-post-element-read-function
(apply-partially #'json--check-position position))
(lambda () (json--check-position position)))
(path (catch :json-path
(if string
(json-read-from-string string)
@ -290,38 +286,33 @@ element in a deeply nested structure."
;;; Keywords
(defvar json-keywords '("true" "false" "null")
(defconst json-keywords '("true" "false" "null")
"List of JSON keywords.")
(make-obsolete-variable 'json-keywords "it is no longer used." "28.1")
;; Keyword parsing
;; Characters that can follow a JSON value.
(rx-define json--post-value (| (in "\t\n\r ,]}") eos))
(defun json-read-keyword (keyword)
"Read a JSON keyword at point.
KEYWORD is the keyword expected."
(unless (member keyword json-keywords)
(signal 'json-unknown-keyword (list keyword)))
(mapc (lambda (char)
(when (/= char (json-peek))
(signal 'json-unknown-keyword
(list (save-excursion
(backward-word-strictly 1)
(thing-at-point 'word)))))
(json-advance))
keyword)
(json-skip-whitespace)
(unless (looking-at "\\([],}]\\|$\\)")
(signal 'json-unknown-keyword
(list (save-excursion
(backward-word-strictly 1)
(thing-at-point 'word)))))
(cond ((string-equal keyword "true") t)
((string-equal keyword "false") json-false)
((string-equal keyword "null") json-null)))
"Read the expected JSON KEYWORD at point."
(prog1 (cond ((equal keyword "true") t)
((equal keyword "false") json-false)
((equal keyword "null") json-null)
(t (signal 'json-unknown-keyword (list keyword))))
(or (looking-at-p keyword)
(signal 'json-unknown-keyword (list (thing-at-point 'word))))
(json-advance (length keyword))
(or (looking-at-p (rx json--post-value))
(signal 'json-unknown-keyword (list (thing-at-point 'word))))
(json-skip-whitespace)))
;; Keyword encoding
(defun json-encode-keyword (keyword)
"Encode KEYWORD as a JSON value."
(declare (side-effect-free t))
(cond ((eq keyword t) "true")
((eq keyword json-false) "false")
((eq keyword json-null) "null")))
@ -330,37 +321,31 @@ KEYWORD is the keyword expected."
;; Number parsing
(defun json-read-number (&optional sign)
"Read the JSON number following point.
The optional SIGN argument is for internal use.
(rx-define json--number
(: (? ?-) ; Sign.
(| (: (in "1-9") (* digit)) ?0) ; Integer.
(? ?. (+ digit)) ; Fraction.
(? (in "Ee") (? (in ?+ ?-)) (+ digit)))) ; Exponent.
N.B.: Only numbers which can fit in Emacs Lisp's native number
representation will be parsed correctly."
;; If SIGN is non-nil, the number is explicitly signed.
(let ((number-regexp
"\\([0-9]+\\)?\\(\\.[0-9]+\\)?\\([Ee][+-]?[0-9]+\\)?"))
(cond ((and (null sign) (= (json-peek) ?-))
(json-advance)
(- (json-read-number t)))
((and (null sign) (= (json-peek) ?+))
(json-advance)
(json-read-number t))
((and (looking-at number-regexp)
(or (match-beginning 1)
(match-beginning 2)))
(goto-char (match-end 0))
(string-to-number (match-string 0)))
(t (signal 'json-number-format (list (point)))))))
(defun json-read-number (&optional _sign)
"Read the JSON number following point."
(declare (advertised-calling-convention () "28.1"))
(or (looking-at (rx json--number))
(signal 'json-number-format (list (point))))
(goto-char (match-end 0))
(prog1 (string-to-number (match-string 0))
(or (looking-at-p (rx json--post-value))
(signal 'json-number-format (list (point))))
(json-skip-whitespace)))
;; Number encoding
(defun json-encode-number (number)
"Return a JSON representation of NUMBER."
(format "%s" number))
(defalias 'json-encode-number #'number-to-string
"Return a JSON representation of NUMBER.")
;;; Strings
(defvar json-special-chars
(defconst json-special-chars
'((?\" . ?\")
(?\\ . ?\\)
(?b . ?\b)
@ -368,7 +353,7 @@ representation will be parsed correctly."
(?n . ?\n)
(?r . ?\r)
(?t . ?\t))
"Characters which are escaped in JSON, with their elisp counterparts.")
"Characters which are escaped in JSON, with their Elisp counterparts.")
;; String parsing
@ -378,48 +363,47 @@ representation will be parsed correctly."
(defun json-read-escaped-char ()
"Read the JSON string escaped character at point."
;; Skip over the '\'
;; Skip over the '\'.
(json-advance)
(let* ((char (json-pop))
(special (assq char json-special-chars)))
(let ((char (json-pop)))
(cond
(special (cdr special))
((not (eq char ?u)) char)
((cdr (assq char json-special-chars)))
((/= char ?u) char)
;; Special-case UTF-16 surrogate pairs,
;; cf. <https://tools.ietf.org/html/rfc7159#section-7>. Note that
;; this clause overlaps with the next one and therefore has to
;; come first.
((looking-at
(rx (group (any "Dd") (any "89ABab") (= 2 (any xdigit)))
"\\u" (group (any "Dd") (any "C-Fc-f") (= 2 (any xdigit)))))
(rx (group (any "Dd") (any "89ABab") (= 2 xdigit))
"\\u" (group (any "Dd") (any "C-Fc-f") (= 2 xdigit))))
(json-advance 10)
(json--decode-utf-16-surrogates
(string-to-number (match-string 1) 16)
(string-to-number (match-string 2) 16)))
((looking-at (rx (= 4 xdigit)))
(let ((hex (match-string 0)))
(json-advance 4)
(string-to-number hex 16)))
(json-advance 4)
(string-to-number (match-string 0) 16))
(t
(signal 'json-string-escape (list (point)))))))
(defun json-read-string ()
"Read the JSON string at point."
(unless (= (json-peek) ?\")
(signal 'json-string-format (list "doesn't start with `\"'!")))
;; Skip over the '"'
;; Skip over the '"'.
(json-advance)
(let ((characters '())
(char (json-peek)))
(while (not (= char ?\"))
(while (/= char ?\")
(when (< char 32)
(signal 'json-string-format (list (prin1-char char))))
(if (zerop char)
(signal 'json-end-of-file ())
(signal 'json-string-format (list char))))
(push (if (= char ?\\)
(json-read-escaped-char)
(json-pop))
(json-advance)
char)
characters)
(setq char (json-peek)))
;; Skip over the '"'
;; Skip over the '"'.
(json-advance)
(if characters
(concat (nreverse characters))
@ -427,29 +411,47 @@ representation will be parsed correctly."
;; String encoding
;; Escape only quotation mark, backslash, and the control
;; characters U+0000 to U+001F (RFC 4627, ECMA-404).
(rx-define json--escape (in ?\" ?\\ cntrl))
(defvar json--long-string-threshold 200
"Length above which strings are considered long for JSON encoding.
It is generally faster to manipulate such strings in a buffer
rather than directly.")
(defvar json--string-buffer nil
"Buffer used for encoding Lisp strings as JSON.
Initialized lazily by `json-encode-string'.")
(defun json-encode-string (string)
"Return a JSON representation of STRING."
;; Reimplement the meat of `replace-regexp-in-string', for
;; performance (bug#20154).
(let ((l (length string))
(start 0)
res mb)
;; Only escape quotation mark, backslash and the control
;; characters U+0000 to U+001F (RFC 4627, ECMA-404).
(while (setq mb (string-match "[\"\\[:cntrl:]]" string start))
(let* ((c (aref string mb))
(special (rassq c json-special-chars)))
(push (substring string start mb) res)
(push (if special
;; Special JSON character (\n, \r, etc.).
(string ?\\ (car special))
;; Fallback: UCS code point in \uNNNN form.
(format "\\u%04x" c))
res)
(setq start (1+ mb))))
(push (substring string start l) res)
(push "\"" res)
(apply #'concat "\"" (nreverse res))))
;; Try to avoid buffer overhead in trivial cases, while also
;; avoiding searching pathological strings for escape characters.
;; Since `string-match-p' doesn't take a LIMIT argument, we use
;; string length as our heuristic. See also bug#20154.
(if (and (< (length string) json--long-string-threshold)
(not (string-match-p (rx json--escape) string)))
(concat "\"" string "\"")
(with-current-buffer
(or json--string-buffer
(with-current-buffer (generate-new-buffer " *json-string*")
;; This seems to afford decent performance gains.
(setq-local inhibit-modification-hooks t)
(setq json--string-buffer (current-buffer))))
(insert ?\" string)
(goto-char (1+ (point-min)))
(while (re-search-forward (rx json--escape) nil 'move)
(let ((char (preceding-char)))
(delete-char -1)
(insert ?\\ (or
;; Special JSON character (\n, \r, etc.).
(car (rassq char json-special-chars))
;; Fallback: UCS code point in \uNNNN form.
(format "u%04x" char)))))
(insert ?\")
;; Empty buffer for next invocation.
(delete-and-extract-region (point-min) (point-max)))))
(defun json-encode-key (object)
"Return a JSON representation of OBJECT.
@ -460,15 +462,13 @@ this signals `json-key-format'."
(signal 'json-key-format (list object)))
encoded))
;;; JSON Objects
;;; Objects
(defun json-new-object ()
"Create a new Elisp object corresponding to a JSON object.
"Create a new Elisp object corresponding to an empty JSON object.
Please see the documentation of `json-object-type'."
(cond ((eq json-object-type 'hash-table)
(make-hash-table :test 'equal))
(t
())))
(and (eq json-object-type 'hash-table)
(make-hash-table :test #'equal)))
(defun json-add-to-object (object key value)
"Add a new KEY -> VALUE association to OBJECT.
@ -476,10 +476,10 @@ Returns the updated object, which you should save, e.g.:
(setq obj (json-add-to-object obj \"foo\" \"bar\"))
Please see the documentation of `json-object-type' and `json-key-type'."
(let ((json-key-type
(or json-key-type
(cdr (assq json-object-type '((hash-table . string)
(alist . symbol)
(plist . keyword)))))))
(cond (json-key-type)
((eq json-object-type 'hash-table) 'string)
((eq json-object-type 'alist) 'symbol)
((eq json-object-type 'plist) 'keyword))))
(setq key
(cond ((eq json-key-type 'string)
key)
@ -499,13 +499,13 @@ Please see the documentation of `json-object-type' and `json-key-type'."
(defun json-read-object ()
"Read the JSON object at point."
;; Skip over the "{"
;; Skip over the '{'.
(json-advance)
(json-skip-whitespace)
;; read key/value pairs until "}"
;; Read key/value pairs until '}'.
(let ((elements (json-new-object))
key value)
(while (not (= (json-peek) ?}))
(while (/= (json-peek) ?\})
(json-skip-whitespace)
(setq key (json-read-string))
(json-skip-whitespace)
@ -520,94 +520,94 @@ Please see the documentation of `json-object-type' and `json-key-type'."
(funcall json-post-element-read-function))
(setq elements (json-add-to-object elements key value))
(json-skip-whitespace)
(when (/= (json-peek) ?})
(when (/= (json-peek) ?\})
(if (= (json-peek) ?,)
(json-advance)
(signal 'json-object-format (list "," (json-peek))))))
;; Skip over the "}"
;; Skip over the '}'.
(json-advance)
(pcase json-object-type
('alist (nreverse elements))
('plist (json--plist-reverse elements))
('plist (json--plist-nreverse elements))
(_ elements))))
;; Hash table encoding
(defun json-encode-hash-table (hash-table)
"Return a JSON representation of HASH-TABLE."
(if json-encoding-object-sort-predicate
(json-encode-alist (map-into hash-table 'list))
(format "{%s%s}"
(json-join
(let (r)
(json--with-indentation
(maphash
(lambda (k v)
(push (format
(if json-encoding-pretty-print
"%s%s: %s"
"%s%s:%s")
json--encoding-current-indentation
(json-encode-key k)
(json-encode v))
r))
hash-table))
r)
json-encoding-separator)
(if (or (not json-encoding-pretty-print)
json-encoding-lisp-style-closings)
""
json--encoding-current-indentation))))
(cond ((hash-table-empty-p hash-table) "{}")
(json-encoding-object-sort-predicate
(json--encode-alist (map-pairs hash-table) t))
(t
(let ((kv-sep (if json-encoding-pretty-print ": " ":"))
result)
(json--with-indentation
(maphash
(lambda (k v)
(push (concat json--encoding-current-indentation
(json-encode-key k)
kv-sep
(json-encode v))
result))
hash-table))
(concat "{"
(string-join (nreverse result) json-encoding-separator)
(and json-encoding-pretty-print
(not json-encoding-lisp-style-closings)
json--encoding-current-indentation)
"}")))))
;; List encoding (including alists and plists)
(defun json-encode-alist (alist)
"Return a JSON representation of ALIST."
(defun json--encode-alist (alist &optional destructive)
"Return a JSON representation of ALIST.
DESTRUCTIVE non-nil means it is safe to modify ALIST by
side-effects."
(when json-encoding-object-sort-predicate
(setq alist
(sort alist (lambda (a b)
(setq alist (sort (if destructive alist (copy-sequence alist))
(lambda (a b)
(funcall json-encoding-object-sort-predicate
(car a) (car b))))))
(format "{%s%s}"
(json-join
(json--with-indentation
(mapcar (lambda (cons)
(format (if json-encoding-pretty-print
"%s%s: %s"
"%s%s:%s")
json--encoding-current-indentation
(json-encode-key (car cons))
(json-encode (cdr cons))))
alist))
json-encoding-separator)
(if (or (not json-encoding-pretty-print)
json-encoding-lisp-style-closings)
""
json--encoding-current-indentation)))
(concat "{"
(let ((kv-sep (if json-encoding-pretty-print ": " ":")))
(json--with-indentation
(mapconcat (lambda (cons)
(concat json--encoding-current-indentation
(json-encode-key (car cons))
kv-sep
(json-encode (cdr cons))))
alist
json-encoding-separator)))
(and json-encoding-pretty-print
(not json-encoding-lisp-style-closings)
json--encoding-current-indentation)
"}"))
(defun json-encode-alist (alist)
"Return a JSON representation of ALIST."
(if alist (json--encode-alist alist) "{}"))
(defun json-encode-plist (plist)
"Return a JSON representation of PLIST."
(if json-encoding-object-sort-predicate
(json-encode-alist (json--plist-to-alist plist))
(let (result)
(json--with-indentation
(while plist
(push (concat
json--encoding-current-indentation
(json-encode-key (car plist))
(if json-encoding-pretty-print
": "
":")
(json-encode (cadr plist)))
(cond ((null plist) "{}")
(json-encoding-object-sort-predicate
(json--encode-alist (map-pairs plist) t))
(t
(let ((kv-sep (if json-encoding-pretty-print ": " ":"))
result)
(setq plist (cddr plist))))
(concat "{"
(json-join (nreverse result) json-encoding-separator)
(if (and json-encoding-pretty-print
(not json-encoding-lisp-style-closings))
json--encoding-current-indentation
"")
"}"))))
(json--with-indentation
(while plist
(push (concat json--encoding-current-indentation
(json-encode-key (pop plist))
kv-sep
(json-encode (pop plist)))
result)))
(concat "{"
(string-join (nreverse result) json-encoding-separator)
(and json-encoding-pretty-print
(not json-encoding-lisp-style-closings)
json--encoding-current-indentation)
"}")))))
(defun json-encode-list (list)
"Return a JSON representation of LIST.
@ -625,15 +625,17 @@ become JSON objects."
(defun json-read-array ()
"Read the JSON array at point."
;; Skip over the "["
;; Skip over the '['.
(json-advance)
(json-skip-whitespace)
;; read values until "]"
(let (elements)
(while (not (= (json-peek) ?\]))
;; Read values until ']'.
(let (elements
(len 0))
(while (/= (json-peek) ?\])
(json-skip-whitespace)
(when json-pre-element-read-function
(funcall json-pre-element-read-function (length elements)))
(funcall json-pre-element-read-function len)
(setq len (1+ len)))
(push (json-read) elements)
(when json-post-element-read-function
(funcall json-post-element-read-function))
@ -641,8 +643,8 @@ become JSON objects."
(when (/= (json-peek) ?\])
(if (= (json-peek) ?,)
(json-advance)
(signal 'json-array-format (list ?, (json-peek))))))
;; Skip over the "]"
(signal 'json-array-format (list "," (json-peek))))))
;; Skip over the ']'.
(json-advance)
(pcase json-array-type
('vector (nreverse (vconcat elements)))
@ -653,42 +655,43 @@ become JSON objects."
(defun json-encode-array (array)
"Return a JSON representation of ARRAY."
(if (and json-encoding-pretty-print
(> (length array) 0))
(not (seq-empty-p array)))
(concat
"["
(json--with-indentation
(concat (format "[%s" json--encoding-current-indentation)
(json-join (mapcar 'json-encode array)
(format "%s%s"
json-encoding-separator
(concat json--encoding-current-indentation
(mapconcat #'json-encode array
(concat json-encoding-separator
json--encoding-current-indentation))))
(format "%s]"
(if json-encoding-lisp-style-closings
""
json--encoding-current-indentation)))
(unless json-encoding-lisp-style-closings
json--encoding-current-indentation)
"]")
(concat "["
(mapconcat 'json-encode array json-encoding-separator)
(mapconcat #'json-encode array json-encoding-separator)
"]")))
;;; JSON reader.
;;; Reader
(defmacro json-readtable-dispatch (char)
"Dispatch reader function for CHAR."
(declare (debug (symbolp)))
(let ((table
'((?t json-read-keyword "true")
(?f json-read-keyword "false")
(?n json-read-keyword "null")
(?{ json-read-object)
(?\[ json-read-array)
(?\" json-read-string)))
res)
(dolist (c '(?- ?+ ?. ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
(push (list c 'json-read-number) table))
(pcase-dolist (`(,c . ,rest) table)
(push `((eq ,char ,c) (,@rest)) res))
`(cond ,@res (t (signal 'json-readtable-error (list ,char))))))
"Dispatch reader function for CHAR at point.
If CHAR is nil, signal `json-end-of-file'."
(declare (debug t))
(macroexp-let2 nil char char
`(cond ,@(map-apply
(lambda (key expr)
`((eq ,char ,key) ,expr))
`((?\" ,#'json-read-string)
(?\[ ,#'json-read-array)
(?\{ ,#'json-read-object)
(?n ,#'json-read-keyword "null")
(?f ,#'json-read-keyword "false")
(?t ,#'json-read-keyword "true")
,@(mapcar (lambda (c) (list c #'json-read-number))
'(?- ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))))
(,char (signal 'json-readtable-error (list ,char)))
(t (signal 'json-end-of-file ())))))
(defun json-read ()
"Parse and return the JSON object following point.
@ -706,10 +709,7 @@ you will get the following structure returned:
((c . :json-false))])
(b . \"foo\"))"
(json-skip-whitespace)
(let ((char (json-peek)))
(if (zerop char)
(signal 'json-end-of-file nil)
(json-readtable-dispatch char))))
(json-readtable-dispatch (char-after)))
;; Syntactic sugar for the reader
@ -724,12 +724,11 @@ you will get the following structure returned:
"Read the first JSON object contained in FILE and return it."
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(json-read)))
;;; JSON encoder
;;; Encoder
(defun json-encode (object)
"Return a JSON representation of OBJECT as a string.
@ -737,20 +736,21 @@ you will get the following structure returned:
OBJECT should have a structure like one returned by `json-read'.
If an error is detected during encoding, an error based on
`json-error' is signaled."
(cond ((memq object (list t json-null json-false))
(json-encode-keyword object))
((stringp object) (json-encode-string object))
((keywordp object) (json-encode-string
(substring (symbol-name object) 1)))
((listp object) (json-encode-list object))
((symbolp object) (json-encode-string
(symbol-name object)))
((numberp object) (json-encode-number object))
((arrayp object) (json-encode-array object))
((hash-table-p object) (json-encode-hash-table object))
(t (signal 'json-error (list object)))))
(cond ((eq object t) (json-encode-keyword object))
((eq object json-null) (json-encode-keyword object))
((eq object json-false) (json-encode-keyword object))
((stringp object) (json-encode-string object))
((keywordp object) (json-encode-string
(substring (symbol-name object) 1)))
((listp object) (json-encode-list object))
((symbolp object) (json-encode-string
(symbol-name object)))
((numberp object) (json-encode-number object))
((arrayp object) (json-encode-array object))
((hash-table-p object) (json-encode-hash-table object))
(t (signal 'json-error (list object)))))
;; Pretty printing & minimizing
;;; Pretty printing & minimizing
(defun json-pretty-print-buffer (&optional minimize)
"Pretty-print current buffer.
@ -769,9 +769,9 @@ MAX-SECS.")
With prefix argument MINIMIZE, minimize it instead."
(interactive "r\nP")
(let ((json-encoding-pretty-print (null minimize))
;; Distinguish an empty objects from 'null'
;; Distinguish an empty object from 'null'.
(json-null :json-null)
;; Ensure that ordering is maintained
;; Ensure that ordering is maintained.
(json-object-type 'alist)
(orig-buf (current-buffer))
error)
@ -800,9 +800,7 @@ With prefix argument MINIMIZE, minimize it instead."
;; them.
(let ((space (buffer-substring
(point)
(+ (point)
(skip-chars-forward
" \t\n" (point-max)))))
(+ (point) (skip-chars-forward " \t\n"))))
(json (json-read)))
(setq pos (point)) ; End of last good json-read.
(set-buffer tmp-buf)
@ -832,14 +830,14 @@ With prefix argument MINIMIZE, minimize it instead."
"Pretty-print current buffer with object keys ordered.
With prefix argument MINIMIZE, minimize it instead."
(interactive "P")
(let ((json-encoding-object-sort-predicate 'string<))
(let ((json-encoding-object-sort-predicate #'string<))
(json-pretty-print-buffer minimize)))
(defun json-pretty-print-ordered (begin end &optional minimize)
"Pretty-print the region with object keys ordered.
With prefix argument MINIMIZE, minimize it instead."
(interactive "r\nP")
(let ((json-encoding-object-sort-predicate 'string<))
(let ((json-encoding-object-sort-predicate #'string<))
(json-pretty-print begin end minimize)))
(provide 'json)

View file

@ -37,7 +37,6 @@
;;; Code:
(require 'cl-lib)
(require 'json)
(require 'eieio)
(eval-when-compile (require 'subr-x))
(require 'warnings)
@ -470,26 +469,35 @@ With optional CLEANUP, kill any associated buffers."
;;;
(define-error 'jsonrpc-error "jsonrpc-error")
(defun jsonrpc--json-read ()
"Read JSON object in buffer, move point to end of buffer."
;; TODO: I guess we can make these macros if/when jsonrpc.el
;; goes into Emacs core.
(cond ((fboundp 'json-parse-buffer) (json-parse-buffer
:object-type 'plist
:null-object nil
:false-object :json-false))
(t (let ((json-object-type 'plist))
(json-read)))))
(defalias 'jsonrpc--json-read
(if (fboundp 'json-parse-buffer)
(lambda ()
(json-parse-buffer :object-type 'plist
:null-object nil
:false-object :json-false))
(require 'json)
(defvar json-object-type)
(declare-function json-read "json" ())
(lambda ()
(let ((json-object-type 'plist))
(json-read))))
"Read JSON object in buffer, move point to end of buffer.")
(defun jsonrpc--json-encode (object)
"Encode OBJECT into a JSON string."
(cond ((fboundp 'json-serialize) (json-serialize
object
:false-object :json-false
:null-object nil))
(t (let ((json-false :json-false)
(json-null nil))
(json-encode object)))))
(defalias 'jsonrpc--json-encode
(if (fboundp 'json-serialize)
(lambda (object)
(json-serialize object
:false-object :json-false
:null-object nil))
(require 'json)
(defvar json-false)
(defvar json-null)
(declare-function json-encode "json" (object))
(lambda (object)
(let ((json-false :json-false)
(json-null nil))
(json-encode object))))
"Encode OBJECT into a JSON string.")
(cl-defun jsonrpc--reply
(connection id &key (result nil result-supplied-p) (error nil error-supplied-p))

View file

@ -43,13 +43,17 @@
("" . "")
("" . "")
;; Yes these are dirty. But ...
("༎ ༎" . ,(compose-string "༎ ༎" 0 3 [?༎ (Br . Bl) ? (Br . Bl) ?༎]))
("༎ ༎" . ,(compose-string (copy-sequence "༎ ༎")
0 3 [?༎ (Br . Bl) ? (Br . Bl) ?༎]))
("༄༅༅" . ,(compose-string
"࿁࿂࿂࿂" 0 4
(copy-sequence "࿁࿂࿂࿂") 0 4
[?࿁ (Br . Bl) ?࿂ (Br . Bl) ?࿂ (Br . Bl) ?࿂]))
("༄༅" . ,(compose-string "࿁࿂࿂" 0 3 [?࿁ (Br . Bl) ?࿂ (Br . Bl) ?࿂]))
("" . ,(compose-string "࿁࿂༙" 0 3 [?࿁ (Br . Bl) ?࿂ (br . tr) ?༙]))
("" . ,(compose-string "࿁࿂" 0 2 [?࿁ (Br . Bl) ?࿂]))))
("༄༅" . ,(compose-string (copy-sequence "࿁࿂࿂")
0 3 [?࿁ (Br . Bl) ?࿂ (Br . Bl) ?࿂]))
("" . ,(compose-string (copy-sequence "࿁࿂༙")
0 3 [?࿁ (Br . Bl) ?࿂ (br . tr) ?༙]))
("" . ,(compose-string (copy-sequence "࿁࿂")
0 2 [?࿁ (Br . Bl) ?࿂]))))
;;;###autoload
(defun tibetan-char-p (ch)

View file

@ -2580,7 +2580,7 @@ in a tooltip."
:type '(choice
(const :tag "Do not show tooltips" nil)
(const :tag "Show all text" t)
(integer :tag "Show characters (max)" 256))
(integer :tag "Max number of characters to show" 256))
:version "26.1")
(defcustom mouse-drag-and-drop-region-show-cursor t

View file

@ -307,10 +307,10 @@ the default EWW buffer."
(insert (format "Loading %s..." url))
(goto-char (point-min)))
(let ((url-mime-accept-string eww-accept-content-types))
(url-retrieve url 'eww-render
(url-retrieve url #'eww-render
(list url nil (current-buffer)))))
(put 'eww 'browse-url-browser-kind 'internal)
(function-put 'eww 'browse-url-browser-kind 'internal)
(defun eww--dwim-expand-url (url)
(setq url (string-trim url))
@ -375,8 +375,8 @@ engine used."
(let ((region-string (buffer-substring (region-beginning) (region-end))))
(if (not (string-match-p "\\`[ \n\t\r\v\f]*\\'" region-string))
(eww region-string)
(call-interactively 'eww)))
(call-interactively 'eww)))
(call-interactively #'eww)))
(call-interactively #'eww)))
(defun eww-open-in-new-buffer ()
"Fetch link at point in a new EWW buffer."
@ -1013,7 +1013,7 @@ just re-display the HTML already fetched."
(eww-display-html 'utf-8 url (plist-get eww-data :dom)
(point) (current-buffer)))
(let ((url-mime-accept-string eww-accept-content-types))
(url-retrieve url 'eww-render
(url-retrieve url #'eww-render
(list url (point) (current-buffer) encode))))))
;; Form support.
@ -1576,8 +1576,10 @@ If EXTERNAL is double prefix, browse in new buffer."
(cond
((not url)
(message "No link under point"))
((string-match "^mailto:" url)
(browse-url-mail url))
((string-match-p "\\`mailto:" url)
;; This respects the user options `browse-url-handlers'
;; and `browse-url-mailto-function'.
(browse-url url))
((and (consp external) (<= (car external) 4))
(funcall browse-url-secondary-browser-function url)
(shr--blink-link))
@ -1615,7 +1617,7 @@ Use link at point if there is one, else the current page's URL."
(eww-current-url))))
(if (not url)
(message "No URL under point")
(url-retrieve url 'eww-download-callback (list url)))))
(url-retrieve url #'eww-download-callback (list url)))))
(defun eww-download-callback (status url)
(unless (plist-get status :error)
@ -2128,12 +2130,12 @@ entries (if any) will be removed from the list.
Only the properties listed in `eww-desktop-data-save' are included.
Generally, the list should not include the (usually overly large)
:dom, :source and :text properties."
(let ((history (mapcar 'eww-desktop-data-1
(cons eww-data eww-history))))
(list :history (if eww-desktop-remove-duplicates
(cl-remove-duplicates
history :test 'eww-desktop-history-duplicate)
history))))
(let ((history (mapcar #'eww-desktop-data-1
(cons eww-data eww-history))))
(list :history (if eww-desktop-remove-duplicates
(cl-remove-duplicates
history :test #'eww-desktop-history-duplicate)
history))))
(defun eww-restore-desktop (file-name buffer-name misc-data)
"Restore an eww buffer from its desktop file record.

View file

@ -135,7 +135,7 @@ same domain as the main data."
This is used for cid: URLs, and the function is called with the
cid: URL as the argument.")
(defvar shr-put-image-function 'shr-put-image
(defvar shr-put-image-function #'shr-put-image
"Function called to put image and alt string.")
(defface shr-strike-through '((t :strike-through t))
@ -365,25 +365,20 @@ If the URL is already at the front of the kill ring act like
(shr-copy-url url)))
(defun shr--current-link-region ()
(let ((current (get-text-property (point) 'shr-url))
start)
(save-excursion
;; Go to the beginning.
(while (and (not (bobp))
(equal (get-text-property (point) 'shr-url) current))
(forward-char -1))
(unless (equal (get-text-property (point) 'shr-url) current)
(forward-char 1))
(setq start (point))
;; Go to the end.
(while (and (not (eobp))
(equal (get-text-property (point) 'shr-url) current))
(forward-char 1))
(list start (point)))))
"Return the start and end positions of the URL at point, if any.
Value is a pair of positions (START . END) if there is a non-nil
`shr-url' text property at point; otherwise nil."
(when (get-text-property (point) 'shr-url)
(let* ((end (or (next-single-property-change (point) 'shr-url)
(point-max)))
(beg (or (previous-single-property-change end 'shr-url)
(point-min))))
(cons beg end))))
(defun shr--blink-link ()
(let* ((region (shr--current-link-region))
(overlay (make-overlay (car region) (cadr region))))
"Briefly fontify URL at point with the face `shr-selected-link'."
(when-let* ((region (shr--current-link-region))
(overlay (make-overlay (car region) (cdr region))))
(overlay-put overlay 'face 'shr-selected-link)
(run-at-time 1 nil (lambda ()
(delete-overlay overlay)))))
@ -437,7 +432,7 @@ the URL of the image to the kill buffer instead."
(if (not url)
(message "No image under point")
(message "Inserting %s..." url)
(url-retrieve url 'shr-image-fetched
(url-retrieve url #'shr-image-fetched
(list (current-buffer) (1- (point)) (point-marker))
t))))
@ -463,7 +458,7 @@ size, and full-buffer size."
(when (> (- (point) start) 2)
(delete-region start (1- (point)))))
(message "Inserting %s..." url)
(url-retrieve url 'shr-image-fetched
(url-retrieve url #'shr-image-fetched
(list (current-buffer) (1- (point)) (point-marker)
(list (cons 'size
(cond ((or (eq size 'default)
@ -493,7 +488,7 @@ size, and full-buffer size."
((fboundp function)
(apply function dom args))
(t
(apply 'shr-generic dom args)))))
(apply #'shr-generic dom args)))))
(defun shr-descend (dom)
(let ((function
@ -730,9 +725,10 @@ size, and full-buffer size."
(let ((gap-start (point))
(face (get-text-property (point) 'face)))
;; Extend the background to the end of the line.
(if face
(insert (propertize "\n" 'face (shr-face-background face)))
(insert "\n"))
(insert ?\n)
(when face
(put-text-property (1- (point)) (point)
'face (shr-face-background face)))
(shr-indent)
(when (and (> (1- gap-start) (point-min))
(get-text-property (point) 'shr-url)
@ -935,12 +931,11 @@ size, and full-buffer size."
(defun shr-indent ()
(when (> shr-indentation 0)
(insert
(if (not shr-use-fonts)
(make-string shr-indentation ?\s)
(propertize " "
'display
`(space :width (,shr-indentation)))))))
(if (not shr-use-fonts)
(insert-char ?\s shr-indentation)
(insert ?\s)
(put-text-property (1- (point)) (point)
'display `(space :width (,shr-indentation))))))
(defun shr-fontize-dom (dom &rest types)
(let ((start (point)))
@ -987,16 +982,11 @@ the mouse click event."
(cond
((not url)
(message "No link under point"))
((string-match "^mailto:" url)
(browse-url-mail url))
(external
(funcall browse-url-secondary-browser-function url)
(shr--blink-link))
(t
(if external
(progn
(funcall browse-url-secondary-browser-function url)
(shr--blink-link))
(browse-url url (if new-window
(not browse-url-new-window-flag)
browse-url-new-window-flag)))))))
(browse-url url (xor new-window browse-url-new-window-flag))))))
(defun shr-save-contents (directory)
"Save the contents from URL in a file."
@ -1005,7 +995,7 @@ the mouse click event."
(if (not url)
(message "No link under point")
(url-retrieve (shr-encode-url url)
'shr-store-contents (list url directory)))))
#'shr-store-contents (list url directory)))))
(defun shr-store-contents (status url directory)
(unless (plist-get status :error)
@ -1156,7 +1146,6 @@ width/height instead."
;; url-cache-extract autoloads url-cache.
(declare-function url-cache-create-filename "url-cache" (url))
(autoload 'browse-url-mail "browse-url")
(defun shr-get-image-data (url)
"Get image data for URL.
@ -1230,7 +1219,7 @@ START, and END. Note that START and END should be markers."
(funcall shr-put-image-function
image (buffer-substring start end))
(delete-region (point) end))))
(url-retrieve url 'shr-image-fetched
(url-retrieve url #'shr-image-fetched
(list (current-buffer) start end)
t t)))))
@ -1679,7 +1668,7 @@ The preference is a float determined from `shr-prefer-media-type'."
(or alt "")))
(insert " ")
(url-queue-retrieve
(shr-encode-url url) 'shr-image-fetched
(shr-encode-url url) #'shr-image-fetched
(list (current-buffer) start (set-marker (make-marker) (point))
(list :width width :height height))
t
@ -2006,12 +1995,11 @@ BASE is the URL of the HTML being rendered."
(cond
((null tbodies)
dom)
((= (length tbodies) 1)
((null (cdr tbodies))
(car tbodies))
(t
;; Table with multiple tbodies. Convert into a single tbody.
`(tbody nil ,@(cl-reduce 'append
(mapcar 'dom-non-text-children tbodies)))))))
`(tbody nil ,@(mapcan #'dom-non-text-children tbodies))))))
(defun shr--fix-tbody (tbody)
(nconc (list 'tbody (dom-attributes tbody))
@ -2311,8 +2299,8 @@ flags that control whether to collect or render objects."
(dolist (column row)
(aset natural-widths i (max (aref natural-widths i) column))
(setq i (1+ i)))))
(let ((extra (- (apply '+ (append suggested-widths nil))
(apply '+ (append widths nil))
(let ((extra (- (apply #'+ (append suggested-widths nil))
(apply #'+ (append widths nil))
(* shr-table-separator-pixel-width (1+ (length widths)))))
(expanded-columns 0))
;; We have extra, unused space, so divide this space amongst the

View file

@ -109,7 +109,7 @@
(eval-when-compile (require 'cl-lib))
;; Sometimes, compilation fails with "Variable binding depth exceeds
;; max-specpdl-size".
;; max-specpdl-size". Shall be fixed in Emacs 27.
(eval-and-compile
(let ((max-specpdl-size (* 2 max-specpdl-size))) (require 'tramp-gvfs)))
@ -318,7 +318,10 @@ arguments to pass to the OPERATION."
(let* ((filename (apply #'tramp-archive-file-name-for-operation
operation args))
(archive (tramp-archive-file-name-archive filename)))
(archive (tramp-archive-file-name-archive filename))
;; Sometimes, it fails with "Variable binding depth exceeds
;; max-specpdl-size". Shall be fixed in Emacs 27.
(max-specpdl-size (* 2 max-specpdl-size)))
;; `filename' could be a quoted file name. Or the file
;; archive could be a directory, see Bug#30293.

View file

@ -477,7 +477,18 @@ file names."
(with-tramp-connection-property
(tramp-get-connection-process vec) "rclone-pid"
(catch 'pid
(dolist (pid (list-system-processes)) ;; "pidof rclone" ?
(dolist
(pid
;; Until Emacs 25, `process-attributes' could
;; crash Emacs for some processes. So we use
;; "pidof", which might not work everywhere.
(if (<= emacs-major-version 25)
(let ((default-directory temporary-file-directory))
(mapcar
#'string-to-number
(split-string
(shell-command-to-string "pidof rclone"))))
(list-system-processes)))
(and (string-match-p
(regexp-quote
(format "rclone mount %s:" (tramp-file-name-host vec)))

View file

@ -1,4 +1,4 @@
;;; webjump.el --- programmable Web hotlist
;;; webjump.el --- programmable Web hotlist -*- lexical-binding: t; -*-
;; Copyright (C) 1996-1997, 2001-2020 Free Software Foundation, Inc.
@ -323,8 +323,7 @@ Please submit bug reports and other feedback to the author, Neil W. Van Dyke
(defun webjump-read-url-choice (what urls &optional default)
;; Note: Convert this to use `webjump-read-choice' someday.
(let* ((completions (mapcar (function (lambda (n) (cons n n)))
urls))
(let* ((completions (mapcar (lambda (n) (cons n n)) urls))
(input (completing-read (concat what
;;(if default " (RET for default)" "")
": ")

View file

@ -1,292 +0,0 @@
;;; levents.el --- emulate the Lucid event data type and associated functions
;; Copyright (C) 1993, 2001-2020 Free Software Foundation, Inc.
;; Maintainer: emacs-devel@gnu.org
;; Keywords: emulations
;; Obsolete-since: 23.2
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Things we cannot emulate in Lisp:
;; It is not possible to emulate current-mouse-event as a variable,
;; though it is not hard to obtain the data from (this-command-keys).
;; We do not have a variable unread-command-event;
;; instead, we have the more general unread-command-events.
;; Our read-key-sequence and read-char are not precisely
;; compatible with those in Lucid Emacs, but they should work ok.
;;; Code:
(defun next-command-event (event)
(error "You must rewrite to use `read-command-event' instead of `next-command-event'"))
(defun next-event (event)
(error "You must rewrite to use `read-event' instead of `next-event'"))
(defun dispatch-event (event)
(error "`dispatch-event' not supported"))
;; Make events of type eval, menu and timeout
;; execute properly.
(define-key global-map [menu] 'execute-eval-event)
(define-key global-map [timeout] 'execute-eval-event)
(define-key global-map [eval] 'execute-eval-event)
(defun execute-eval-event (event)
(interactive "e")
(funcall (nth 1 event) (nth 2 event)))
(put 'eval 'event-symbol-elements '(eval))
(put 'menu 'event-symbol-elements '(eval))
(put 'timeout 'event-symbol-elements '(eval))
(defun allocate-event ()
"Return an empty event structure.
In this emulation, it returns nil."
nil)
(defun button-press-event-p (obj)
"True if the argument is a mouse-button-press event object."
(and (consp obj) (symbolp (car obj))
(memq 'down (get (car obj) 'event-symbol-elements))))
(defun button-release-event-p (obj)
"True if the argument is a mouse-button-release event object."
(and (consp obj) (symbolp (car obj))
(or (memq 'click (get (car obj) 'event-symbol-elements))
(memq 'drag (get (car obj) 'event-symbol-elements)))))
(defun button-event-p (obj)
"True if the argument is a mouse-button press or release event object."
(and (consp obj) (symbolp (car obj))
(or (memq 'click (get (car obj) 'event-symbol-elements))
(memq 'down (get (car obj) 'event-symbol-elements))
(memq 'drag (get (car obj) 'event-symbol-elements)))))
(defun mouse-event-p (obj)
"True if the argument is a mouse-button press or release event object."
(and (consp obj) (symbolp (car obj))
(or (eq (car obj) 'mouse-movement)
(memq 'click (get (car obj) 'event-symbol-elements))
(memq 'down (get (car obj) 'event-symbol-elements))
(memq 'drag (get (car obj) 'event-symbol-elements)))))
(defun character-to-event (ch &optional event)
"Converts a numeric ASCII value to an event structure, replete with
bucky bits. The character is the first argument, and the event to fill
in is the second. This function contains knowledge about what the codes
mean -- for example, the number 9 is converted to the character Tab,
not the distinct character Control-I.
Beware that character-to-event and event-to-character are not strictly
inverse functions, since events contain much more information than the
ASCII character set can encode."
ch)
(defun copy-event (event1 &optional event2)
"Make a copy of the given event object.
In this emulation, `copy-event' just returns its argument."
event1)
(defun deallocate-event (event)
"Allow the given event structure to be reused.
In actual Lucid Emacs, you MUST NOT use this event object after
calling this function with it. You will lose. It is not necessary to
call this function, as event objects are garbage- collected like all
other objects; however, it may be more efficient to explicitly
deallocate events when you are sure that this is safe.
This emulation does not actually deallocate or reuse events
except via garbage collection and `cons'."
nil)
(defun enqueue-eval-event: (function object)
"Add an eval event to the back of the queue.
It will be the next event read after all pending events."
(setq unread-command-events
(nconc unread-command-events
(list (list 'eval function object)))))
(defun eval-event-p (obj)
"True if the argument is an eval or menu event object."
(eq (car-safe obj) 'eval))
(defun event-button (event)
"Return the button-number of the given mouse-button-press event."
(let ((sym (car (get (car event) 'event-symbol-elements))))
(cdr (assq sym '((mouse-1 . 1) (mouse-2 . 2) (mouse-3 . 3)
(mouse-4 . 4) (mouse-5 . 5))))))
(defun event-function (event)
"Return the callback function of the given timeout, menu, or eval event."
(nth 1 event))
(defun event-key (event)
"Return the KeySym of the given key-press event.
The value is an ASCII printing character (not upper case) or a symbol."
(if (symbolp event)
(car (get event 'event-symbol-elements))
(let ((base (logand event (1- (ash 1 18)))))
(downcase (if (< base 32) (logior base 64) base)))))
(defun event-object (event)
"Return the function argument of the given timeout, menu, or eval event."
(nth 2 event))
(defun event-point (event)
"Return the character position of the given mouse-related event.
If the event did not occur over a window, or did
not occur over text, then this returns nil. Otherwise, it returns an index
into the buffer visible in the event's window."
(posn-point (event-end event)))
;; Return position of start of line LINE in WINDOW.
;; If LINE is nil, return the last position
;; visible in WINDOW.
(defun event-closest-point-1 (window &optional line)
(let* ((total (- (window-height window)
(if (window-minibuffer-p window)
0 1)))
(distance (or line total)))
(save-excursion
(goto-char (window-start window))
(if (= (vertical-motion distance) distance)
(if (not line)
(forward-char -1)))
(point))))
(defun event-closest-point (event &optional start-window)
"Return the nearest position to where EVENT ended its motion.
This is computed for the window where EVENT's motion started,
or for window WINDOW if that is specified."
(or start-window (setq start-window (posn-window (event-start event))))
(if (eq start-window (posn-window (event-end event)))
(if (eq (event-point event) 'vertical-line)
(event-closest-point-1 start-window
(cdr (posn-col-row (event-end event))))
(if (eq (event-point event) 'mode-line)
(event-closest-point-1 start-window)
(event-point event)))
;; EVENT ended in some other window.
(let* ((end-w (posn-window (event-end event)))
(end-w-top)
(w-top (nth 1 (window-edges start-window))))
(setq end-w-top
(if (windowp end-w)
(nth 1 (window-edges end-w))
(/ (cdr (posn-x-y (event-end event)))
(frame-char-height end-w))))
(if (>= end-w-top w-top)
(event-closest-point-1 start-window)
(window-start start-window)))))
(defun event-process (event)
"Return the process of the given process-output event."
(nth 1 event))
(defun event-timestamp (event)
"Return the timestamp of the given event object.
In Lucid Emacs, this works for any kind of event.
In this emulation, it returns nil for non-mouse-related events."
(and (listp event)
(posn-timestamp (event-end event))))
(defun event-to-character (event &optional lenient)
"Return the closest ASCII approximation to the given event object.
If the event isn't a keypress, this returns nil.
If the second argument is non-nil, then this is lenient in its
translation; it will ignore modifier keys other than control and meta,
and will ignore the shift modifier on those characters which have no
shifted ASCII equivalent (Control-Shift-A for example, will be mapped to
the same ASCII code as Control-A.) If the second arg is nil, then nil
will be returned for events which have no direct ASCII equivalent."
(if (symbolp event)
(and lenient
(cdr (assq event '((backspace . 8) (delete . 127) (tab . 9)
(return . 10) (enter . 10)))))
;; Our interpretation is, ASCII means anything a number can represent.
(if (integerp event)
event nil)))
(defun event-window (event)
"Return the window of the given mouse-related event object."
(posn-window (event-end event)))
(defun event-x (event)
"Return the X position in characters of the given mouse-related event."
(/ (car (posn-col-row (event-end event)))
(frame-char-width (window-frame (event-window event)))))
(defun event-x-pixel (event)
"Return the X position in pixels of the given mouse-related event."
(car (posn-col-row (event-end event))))
(defun event-y (event)
"Return the Y position in characters of the given mouse-related event."
(/ (cdr (posn-col-row (event-end event)))
(frame-char-height (window-frame (event-window event)))))
(defun event-y-pixel (event)
"Return the Y position in pixels of the given mouse-related event."
(cdr (posn-col-row (event-end event))))
(defun key-press-event-p (obj)
"True if the argument is a keyboard event object."
(or (integerp obj)
(and (symbolp obj)
(get obj 'event-symbol-elements))))
(defun menu-event-p (obj)
"True if the argument is a menu event object."
(eq (car-safe obj) 'menu))
(defun motion-event-p (obj)
"True if the argument is a mouse-motion event object."
(eq (car-safe obj) 'mouse-movement))
(defun read-command-event ()
"Return the next keyboard or mouse event; execute other events.
This is similar to the function `next-command-event' of Lucid Emacs,
but different in that it returns the event rather than filling in
an existing event object."
(let (event)
(while (progn
(setq event (read-event))
(not (or (key-press-event-p event)
(button-press-event-p event)
(button-release-event-p event)
(menu-event-p event))))
(let ((type (car-safe event)))
(cond ((eq type 'eval)
(funcall (nth 1 event) (nth 2 event)))
((eq type 'switch-frame)
(select-frame (nth 1 event))))))
event))
(defun process-event-p (obj)
"True if the argument is a process-output event object.
GNU Emacs 19 does not currently generate process-output events."
(eq (car-safe obj) 'process))
(provide 'levents)
;;; levents.el ends here

View file

@ -2995,7 +2995,8 @@ Agenda views are separated by `org-agenda-block-separator'."
(erase-buffer)
(insert (eval-when-compile
(let ((header
"Press key for an agenda command:
(copy-sequence
"Press key for an agenda command:
-------------------------------- < Buffer, subtree/region restriction
a Agenda for current week or day > Remove restriction
t List of all TODO entries e Export agenda views
@ -3004,7 +3005,7 @@ s Search for keywords M Like m, but only TODO entries
/ Multi-occur S Like s, but only TODO entries
? Find :FLAGGED: entries C Configure custom agenda commands
* Toggle sticky agenda views # List stuck projects (!=configure)
")
"))
(start 0))
(while (string-match
"\\(^\\| \\|(\\)\\(\\S-\\)\\( \\|=\\)"

View file

@ -31,7 +31,8 @@
;; ;; Minibuffer prompt for password.
;; => "foo"
;;
;; (password-cache-add "test" (copy-sequence "foo"))
;; (password-cache-add "test" (read-passwd "Password? "))
;; ;; Minibuffer prompt from read-passwd, which returns "foo".
;; => nil
;; (password-read "Password? " "test")

View file

@ -3412,8 +3412,14 @@ regexp should match \"(\" if parentheses are valid in declarators.
The end of the first submatch is taken as the end of the operator.
Identifier syntax is in effect when this is matched (see
`c-identifier-syntax-table')."
t (if (c-lang-const c-type-modifier-kwds)
(concat (regexp-opt (c-lang-const c-type-modifier-kwds) t) "\\>")
t (if (or (c-lang-const c-type-modifier-kwds) (c-lang-const c-modifier-kwds))
(concat
(regexp-opt (c--delete-duplicates
(append (c-lang-const c-type-modifier-kwds)
(c-lang-const c-modifier-kwds))
:test 'string-equal)
t)
"\\>")
;; Default to a regexp that never matches.
regexp-unmatchable)
;; Check that there's no "=" afterwards to avoid matching tokens

View file

@ -795,7 +795,7 @@ compatible with old code; callers should always specify it."
(set (make-local-variable 'outline-level) 'c-outline-level)
(set (make-local-variable 'add-log-current-defun-function)
(lambda ()
(or (c-cpp-define-name) (c-defun-name))))
(or (c-cpp-define-name) (car (c-defun-name-and-limits nil)))))
(let ((rfn (assq mode c-require-final-newline)))
(when rfn
(if (boundp 'mode-require-final-newline)

View file

@ -1,7 +1,7 @@
;;; project.el --- Operations on the current project -*- lexical-binding: t; -*-
;; Copyright (C) 2015-2020 Free Software Foundation, Inc.
;; Version: 0.1.3
;; Version: 0.2.0
;; Package-Requires: ((emacs "26.3"))
;; This is a GNU ELPA :core package. Avoid using functionality that
@ -40,7 +40,7 @@
;; Infrastructure:
;;
;; Function `project-current', to determine the current project
;; instance, and 5 (at the moment) generic functions that act on it.
;; instance, and 4 (at the moment) generic functions that act on it.
;; This list is to be extended in future versions.
;;
;; Utils:
@ -122,14 +122,25 @@ is not a part of a detectable project either, return a
(defun project--find-in-directory (dir)
(run-hook-with-args-until-success 'project-find-functions dir))
(cl-defgeneric project-root (project)
"Return root directory of the current project.
It usually contains the main build file, dependencies
configuration file, etc. Though neither is mandatory.
The directory name must be absolute."
(car (project-roots project)))
(cl-defgeneric project-roots (project)
"Return the list of directory roots of the current project.
"Return the list containing the current project root.
Most often it's just one directory which contains the project
build file and everything else in the project. But in more
advanced configurations, a project can span multiple directories.
The directory names should be absolute.")
The function is obsolete, all projects have one main root anyway,
and the rest should be possible to express through
`project-external-roots'."
;; FIXME: Can we specify project's version here?
;; FIXME: Could we make this affect cl-defmethod calls too?
(declare (obsolete project-root "0.3.0"))
(list (project-root project)))
;; FIXME: Add MODE argument, like in `ede-source-paths'?
(cl-defgeneric project-external-roots (_project)
@ -138,18 +149,14 @@ The directory names should be absolute.")
It's the list of directories outside of the project that are
still related to it. If the project deals with source code then,
depending on the languages used, this list should include the
headers search path, load path, class path, and so on.
The rule of thumb for whether to include a directory here, and
not in `project-roots', is whether its contents are meant to be
edited together with the rest of the project."
headers search path, load path, class path, and so on."
nil)
(cl-defgeneric project-ignores (_project _dir)
"Return the list of glob patterns to ignore inside DIR.
Patterns can match both regular files and directories.
To root an entry, start it with `./'. To match directories only,
end it with `/'. DIR must be one of `project-roots' or
end it with `/'. DIR must be either `project-root' or one of
`project-external-roots'."
;; TODO: Document and support regexp ignores as used by Hg.
;; TODO: Support whitelist entries.
@ -170,13 +177,13 @@ end it with `/'. DIR must be one of `project-roots' or
(t
(complete-with-action action all-files string pred)))))
(cl-defmethod project-roots ((project (head transient)))
(list (cdr project)))
(cl-defmethod project-root ((project (head transient)))
(cdr project))
(cl-defgeneric project-files (project &optional dirs)
"Return a list of files in directories DIRS in PROJECT.
DIRS is a list of absolute directories; it should be some
subset of the project roots and external roots.
subset of the project root and external roots.
The default implementation uses `find-program'. PROJECT is used
to find the list of ignores for each directory."
@ -184,7 +191,8 @@ to find the list of ignores for each directory."
(lambda (dir)
(project--files-in-directory dir
(project--dir-ignores project dir)))
(or dirs (project-roots project))))
(or dirs
(list (project-root project)))))
(defun project--files-in-directory (dir ignores &optional files)
(require 'find-dired)
@ -223,7 +231,7 @@ to find the list of ignores for each directory."
local-files))))
(defgroup project-vc nil
"Project implementation using the VC package."
"Project implementation based on the VC package."
:version "25.1"
:group 'tools)
@ -232,6 +240,15 @@ to find the list of ignores for each directory."
:type '(repeat string)
:safe 'listp)
(defcustom project-vc-merge-submodules t
"Non-nil to consider submodules part of the parent project.
After changing this variable (using Customize or .dir-locals.el)
you might have to restart Emacs to see the effect."
:type 'boolean
:package-version '(project . "0.2.0")
:safe 'booleanp)
;; FIXME: Using the current approach, major modes are supposed to set
;; this variable to a buffer-local value. So we don't have access to
;; the "external roots" of language A from buffers of language B, which
@ -273,38 +290,48 @@ backend implementation of `project-external-roots'.")
(pcase backend
('Git
;; Don't stop at submodule boundary.
;; Note: It's not necessarily clear-cut what should be
;; considered a "submodule" in the sense that some users
;; may setup things equivalent to "git-submodule"s using
;; "git worktree" instead (for example).
;; FIXME: Also it may be the case that some users would consider
;; a submodule as its own project. So there's a good chance
;; we will need to let the user tell us what is their intention.
(or (vc-file-getprop dir 'project-git-root)
(let* ((root (vc-call-backend backend 'root dir))
(gitfile (expand-file-name ".git" root)))
(let ((root (vc-call-backend backend 'root dir)))
(vc-file-setprop
dir 'project-git-root
(cond
((file-directory-p gitfile)
root)
((with-temp-buffer
(insert-file-contents gitfile)
(goto-char (point-min))
;; Kind of a hack to distinguish a submodule from
;; other cases of .git files pointing elsewhere.
(looking-at "gitdir: [./]+/\\.git/modules/"))
(let* ((parent (file-name-directory
(directory-file-name root))))
(vc-call-backend backend 'root parent)))
(t root)))
)))
(if (and
;; FIXME: Invalidate the cache when the value
;; of this variable changes.
project-vc-merge-submodules
(project--submodule-p root))
(let* ((parent (file-name-directory
(directory-file-name root))))
(vc-call-backend backend 'root parent))
root)))))
('nil nil)
(_ (ignore-errors (vc-call-backend backend 'root dir))))))
(and root (cons 'vc root))))
(cl-defmethod project-roots ((project (head vc)))
(list (cdr project)))
(defun project--submodule-p (root)
;; XXX: We only support Git submodules for now.
;;
;; For submodules, at least, we expect the users to prefer them to
;; be considered part of the parent project. For those who don't,
;; there is the custom var now.
;;
;; Some users may also set up things equivalent to Git submodules
;; using "git worktree" (for example). However, we expect that most
;; of them would prefer to treat those as separate projects anyway.
(let* ((gitfile (expand-file-name ".git" root)))
(cond
((file-directory-p gitfile)
nil)
((with-temp-buffer
(insert-file-contents gitfile)
(goto-char (point-min))
;; Kind of a hack to distinguish a submodule from
;; other cases of .git files pointing elsewhere.
(looking-at "gitdir: [./]+/\\.git/modules/"))
t)
(t nil))))
(cl-defmethod project-root ((project (head vc)))
(cdr project))
(cl-defmethod project-external-roots ((project (head vc)))
(project-subtract-directories
@ -312,7 +339,7 @@ backend implementation of `project-external-roots'.")
(mapcar
#'file-name-as-directory
(funcall project-vc-external-roots-function)))
(project-roots project)))
(list (project-root project))))
(cl-defmethod project-files ((project (head vc)) &optional dirs)
(cl-mapcan
@ -330,7 +357,8 @@ backend implementation of `project-external-roots'.")
(project--files-in-directory
dir
(project--dir-ignores project dir)))))
(or dirs (project-roots project))))
(or dirs
(list (project-root project)))))
(declare-function vc-git--program-version "vc-git")
(declare-function vc-git--run-command-string "vc-git")
@ -372,7 +400,9 @@ backend implementation of `project-external-roots'.")
submodules)))
(setq files
(apply #'nconc files sub-files)))
files))
;; 'git ls-files' returns duplicate entries for merge conflicts.
;; XXX: Better solutions welcome, but this seems cheap enough.
(delete-consecutive-dups files)))
(`Hg
(let ((default-directory (expand-file-name (file-name-as-directory dir)))
args)
@ -471,7 +501,7 @@ requires quoting, e.g. `\\[quoted-insert]<space>'."
(let* ((pr (project-current t))
(files
(if (not current-prefix-arg)
(project-files pr (project-roots pr))
(project-files pr)
(let ((dir (read-directory-name "Base directory: "
nil default-directory t)))
(project--files-in-directory dir
@ -482,9 +512,8 @@ requires quoting, e.g. `\\[quoted-insert]<space>'."
nil)))
(defun project--dir-ignores (project dir)
(let* ((roots (project-roots project))
(root (cl-find dir roots :test #'file-in-directory-p)))
(if (not root)
(let ((root (project-root project)))
(if (not (file-in-directory-p dir root))
(project-ignores nil nil) ;The defaults.
(let ((ignores (project-ignores project root)))
(if (file-equal-p root dir)
@ -502,8 +531,8 @@ pattern to search for."
(require 'xref)
(let* ((pr (project-current t))
(files
(project-files pr (append
(project-roots pr)
(project-files pr (cons
(project-root pr)
(project-external-roots pr)))))
(xref--show-xrefs
(apply-partially #'project--find-regexp-in-files regexp files)
@ -541,23 +570,23 @@ pattern to search for."
;;;###autoload
(defun project-find-file ()
"Visit a file (with completion) in the current project's roots.
"Visit a file (with completion) in the current project.
The completion default is the filename at point, if one is
recognized."
(interactive)
(let* ((pr (project-current t))
(dirs (project-roots pr)))
(dirs (list (project-root pr))))
(project-find-file-in (thing-at-point 'filename) dirs pr)))
;;;###autoload
(defun project-or-external-find-file ()
"Visit a file (with completion) in the current project's roots or external roots.
"Visit a file (with completion) in the current project or external roots.
The completion default is the filename at point, if one is
recognized."
(interactive)
(let* ((pr (project-current t))
(dirs (append
(project-roots pr)
(dirs (cons
(project-root pr)
(project-external-roots pr))))
(project-find-file-in (thing-at-point 'filename) dirs pr)))
@ -660,5 +689,13 @@ loop using the command \\[fileloop-continue]."
from to (project-files (project-current t)) 'default)
(fileloop-continue))
;;;###autoload
(defun project-compile ()
"Run `compile' in the project root."
(interactive)
(let* ((pr (project-current t))
(default-directory (project-root pr)))
(call-interactively 'compile)))
(provide 'project)
;;; project.el ends here

View file

@ -261,7 +261,6 @@
(require 'ansi-color)
(require 'cl-lib)
(require 'comint)
(require 'json)
(require 'tramp-sh)
;; Avoid compiler warnings
@ -2276,6 +2275,18 @@ Do not set this variable directly, instead use
Do not set this variable directly, instead use
`python-shell-prompt-set-calculated-regexps'.")
(defalias 'python--parse-json-array
(if (fboundp 'json-parse-string)
(lambda (string)
(json-parse-string string :array-type 'list))
(require 'json)
(defvar json-array-type)
(declare-function json-read-from-string "json" (string))
(lambda (string)
(let ((json-array-type 'list))
(json-read-from-string string))))
"Parse the JSON array in STRING into a Lisp list.")
(defun python-shell-prompt-detect ()
"Detect prompts for the current `python-shell-interpreter'.
When prompts can be retrieved successfully from the
@ -2324,11 +2335,11 @@ detection and just returns nil."
(catch 'prompts
(dolist (line (split-string output "\n" t))
(let ((res
;; Check if current line is a valid JSON array
(and (string= (substring line 0 2) "[\"")
;; Check if current line is a valid JSON array.
(and (string-prefix-p "[\"" line)
(ignore-errors
;; Return prompts as a list, not vector
(append (json-read-from-string line) nil)))))
;; Return prompts as a list.
(python--parse-json-array line)))))
;; The list must contain 3 strings, where the first
;; is the input prompt, the second is the block
;; prompt and the last one is the output prompt. The

View file

@ -186,7 +186,7 @@ and you want to simplify them for the mode line
"Non-nil means display current function name in mode line.
This makes a difference only if `which-function-mode' is non-nil.")
(add-hook 'find-file-hook 'which-func-ff-hook t)
(add-hook 'after-change-major-mode-hook 'which-func-ff-hook t)
(defun which-func-try-to-enable ()
(unless (or (not which-function-mode)
@ -195,7 +195,7 @@ This makes a difference only if `which-function-mode' is non-nil.")
(member major-mode which-func-modes)))))
(defun which-func-ff-hook ()
"File find hook for Which Function mode.
"`after-change-major-mode-hook' for Which Function mode.
It creates the Imenu index for the buffer, if necessary."
(which-func-try-to-enable)
@ -282,52 +282,55 @@ If no function name is found, return nil."
(when (null name)
(setq name (add-log-current-defun)))
;; If Imenu is loaded, try to make an index alist with it.
;; If `add-log-current-defun' ran and gave nil, accept that.
(when (and (null name)
(boundp 'imenu--index-alist)
(or (null imenu--index-alist)
;; Update if outdated
(/= (buffer-chars-modified-tick) imenu-menubar-modified-tick))
(null which-function-imenu-failed))
(ignore-errors (imenu--make-index-alist t))
(unless imenu--index-alist
(set (make-local-variable 'which-function-imenu-failed) t)))
;; If we have an index alist, use it.
(when (and (null name)
(boundp 'imenu--index-alist) imenu--index-alist)
(let ((alist imenu--index-alist)
(minoffset (point-max))
offset pair mark imstack namestack)
;; Elements of alist are either ("name" . marker), or
;; ("submenu" ("name" . marker) ... ). The list can be
;; arbitrarily nested.
(while (or alist imstack)
(if (null alist)
(setq alist (car imstack)
namestack (cdr namestack)
imstack (cdr imstack))
(null add-log-current-defun-function))
(when (and (null name)
(boundp 'imenu--index-alist)
(or (null imenu--index-alist)
;; Update if outdated
(/= (buffer-chars-modified-tick) imenu-menubar-modified-tick))
(null which-function-imenu-failed))
(ignore-errors (imenu--make-index-alist t))
(unless imenu--index-alist
(set (make-local-variable 'which-function-imenu-failed) t)))
;; If we have an index alist, use it.
(when (and (null name)
(boundp 'imenu--index-alist) imenu--index-alist)
(let ((alist imenu--index-alist)
(minoffset (point-max))
offset pair mark imstack namestack)
;; Elements of alist are either ("name" . marker), or
;; ("submenu" ("name" . marker) ... ). The list can be
;; arbitrarily nested.
(while (or alist imstack)
(if (null alist)
(setq alist (car imstack)
namestack (cdr namestack)
imstack (cdr imstack))
(setq pair (car-safe alist)
alist (cdr-safe alist))
(setq pair (car-safe alist)
alist (cdr-safe alist))
(cond
((atom pair)) ; Skip anything not a cons.
(cond
((atom pair)) ; Skip anything not a cons.
((imenu--subalist-p pair)
(setq imstack (cons alist imstack)
namestack (cons (car pair) namestack)
alist (cdr pair)))
((imenu--subalist-p pair)
(setq imstack (cons alist imstack)
namestack (cons (car pair) namestack)
alist (cdr pair)))
((or (number-or-marker-p (setq mark (cdr pair)))
(and (overlayp mark)
(setq mark (overlay-start mark))))
(when (and (>= (setq offset (- (point) mark)) 0)
(< offset minoffset)) ; Find the closest item.
(setq minoffset offset
name (if (null which-func-imenu-joiner-function)
(car pair)
(funcall
which-func-imenu-joiner-function
(reverse (cons (car pair) namestack))))))))))))
((or (number-or-marker-p (setq mark (cdr pair)))
(and (overlayp mark)
(setq mark (overlay-start mark))))
(when (and (>= (setq offset (- (point) mark)) 0)
(< offset minoffset)) ; Find the closest item.
(setq minoffset offset
name (if (null which-func-imenu-joiner-function)
(car pair)
(funcall
which-func-imenu-joiner-function
(reverse (cons (car pair) namestack)))))))))))))
;; Filter the name if requested.
(when name
(if which-func-cleanup-function

View file

@ -268,8 +268,8 @@ find a search tool; by default, this uses \"find | grep\" in the
(lambda (dir)
(xref-references-in-directory identifier dir))
(let ((pr (project-current t)))
(append
(project-roots pr)
(cons
(project-root pr)
(project-external-roots pr)))))
(cl-defgeneric xref-backend-apropos (backend pattern)

View file

@ -4117,7 +4117,11 @@ MODES is as for `set-default-file-modes'."
;; now, but it generates slower code.
(defmacro save-match-data (&rest body)
"Execute the BODY forms, restoring the global value of the match data.
The value returned is the value of the last form in BODY."
The value returned is the value of the last form in BODY.
NOTE: The convention in Elisp is that any function, except for a few
exceptions like car/assoc/+/goto-char, can clobber the match data,
so `save-match-data' should normally be used to save *your* match data
rather than your caller's match data."
;; It is better not to use backquote here,
;; because that makes a bootstrapping problem
;; if you need to recompile all the Lisp files using interpreted code.

View file

@ -1106,6 +1106,7 @@ the *vc-dir* buffer.
(set (make-local-variable 'vc-dir-backend) use-vc-backend)
(set (make-local-variable 'desktop-save-buffer)
'vc-dir-desktop-buffer-misc-data)
(setq-local bookmark-make-record-function #'vc-dir-bookmark-make-record)
(setq buffer-read-only t)
(when (boundp 'tool-bar-map)
(set (make-local-variable 'tool-bar-map) vc-dir-tool-bar-map))
@ -1465,6 +1466,41 @@ These are the commands available for use in the file status buffer:
(add-to-list 'desktop-buffer-mode-handlers
'(vc-dir-mode . vc-dir-restore-desktop-buffer))
;;; Support for bookmark.el (adapted from what info.el does).
(declare-function bookmark-make-record-default
"bookmark" (&optional no-file no-context posn))
(declare-function bookmark-prop-get "bookmark" (bookmark prop))
(declare-function bookmark-default-handler "bookmark" (bmk))
(declare-function bookmark-get-bookmark-record "bookmark" (bmk))
(defun vc-dir-bookmark-make-record ()
"Make record used to bookmark a `vc-dir' buffer.
This implements the `bookmark-make-record-function' type for
`vc-dir' buffers."
(let* ((bookmark-name
(concat "(" (symbol-name vc-dir-backend) ") "
(file-name-nondirectory
(directory-file-name default-directory))))
(defaults (list bookmark-name default-directory)))
`(,bookmark-name
,@(bookmark-make-record-default 'no-file)
(filename . ,default-directory)
(handler . vc-dir-bookmark-jump)
(defaults . ,defaults))))
;;;###autoload
(defun vc-dir-bookmark-jump (bmk)
"Provides the bookmark-jump behavior for a `vc-dir' buffer.
This implements the `handler' function interface for the record
type returned by `vc-dir-bookmark-make-record'."
(let* ((file (bookmark-prop-get bmk 'filename))
(buf (save-window-excursion
(vc-dir file) (current-buffer))))
(bookmark-default-handler
`("" (buffer . ,buf) . ,(bookmark-get-bookmark-record bmk)))))
(provide 'vc-dir)

View file

@ -72,6 +72,7 @@
;; by git, so it's probably
;; not a good idea.
;; - merge-news (file) see `merge-file'
;; - mark-resolved (file) OK
;; - steal-lock (file &optional revision) NOT NEEDED
;; HISTORY FUNCTIONS
;; * print-log (files buffer &optional shortlog start-revision limit) OK
@ -1530,6 +1531,9 @@ This requires git 1.8.4 or later, for the \"-L\" option of \"git log\"."
(defun vc-git-rename-file (old new)
(vc-git-command nil 0 (list old new) "mv" "-f" "--"))
(defun vc-git-mark-resolved (files)
(vc-git-command nil 0 files "add"))
(defvar vc-git-extra-menu-map
(let ((map (make-sparse-keymap)))
(define-key map [git-grep]

View file

@ -498,7 +498,7 @@ status of this file. Otherwise, the value returned is one of:
"Return the repository version from which FILE was checked out.
If FILE is not registered, this function always returns nil."
(or (vc-file-getprop file 'vc-working-revision)
(progn
(let ((default-directory (file-name-directory file)))
(setq backend (or backend (vc-backend file)))
(when backend
(vc-file-setprop file 'vc-working-revision

View file

@ -163,8 +163,4 @@ correspond to the running Emacs.
Optional argument DIR is a directory to use instead of `source-directory'."
(emacs-repository-branch-git (or dir source-directory)))
;; We put version info into the executable in the form that `ident' uses.
(purecopy (concat "\n$Id: " (subst-char-in-string ?\n ?\s (emacs-version))
" $\n"))
;;; version.el ends here

View file

@ -1023,9 +1023,17 @@ entity references (e.g., replace each & with &amp;).
XML character data must not contain & or < characters, nor the >
character under some circumstances. The XML spec does not impose
restriction on \" or \\=', but we just substitute for these too
\(as is permitted by the spec)."
\(as is permitted by the spec).
If STRING contains characters that are invalid in XML (as defined
by https://www.w3.org/TR/xml/#charsets), signal an error of type
`xml-invalid-character'."
(with-temp-buffer
(insert string)
(goto-char (point-min))
(when (re-search-forward
"[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]")
(signal 'xml-invalid-character (list (char-before) (match-beginning 0))))
(dolist (substitution '(("&" . "&amp;")
("<" . "&lt;")
(">" . "&gt;")
@ -1036,6 +1044,9 @@ restriction on \" or \\=', but we just substitute for these too
(replace-match (cdr substitution) t t nil)))
(buffer-string)))
(define-error 'xml-invalid-character "Invalid XML character"
'wrong-type-argument)
(defun xml-debug-print-internal (xml indent-string)
"Outputs the XML tree in the current buffer.
The first line is indented with INDENT-STRING."

View file

@ -3429,23 +3429,6 @@ usage: (vector &rest OBJECTS) */)
return val;
}
void
make_byte_code (struct Lisp_Vector *v)
{
/* Don't allow the global zero_vector to become a byte code object. */
eassert (0 < v->header.size);
if (v->header.size > 1 && STRINGP (v->contents[1])
&& STRING_MULTIBYTE (v->contents[1]))
/* BYTECODE-STRING must have been produced by Emacs 20.2 or the
earlier because they produced a raw 8-bit string for byte-code
and now such a byte-code string is loaded as multibyte while
raw 8-bit characters converted to multibyte form. Thus, now we
must convert them back to the original unibyte form. */
v->contents[1] = Fstring_as_unibyte (v->contents[1]);
XSETPVECTYPE (v, PVEC_COMPILED);
}
DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0,
doc: /* Create a byte-code object with specified arguments as elements.
The arguments should be the ARGLIST, bytecode-string BYTE-CODE, constant
@ -3464,8 +3447,14 @@ stack before executing the byte-code.
usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INTERACTIVE-SPEC &rest ELEMENTS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
Lisp_Object val = make_uninit_vector (nargs);
struct Lisp_Vector *p = XVECTOR (val);
if (! ((FIXNUMP (args[COMPILED_ARGLIST])
|| CONSP (args[COMPILED_ARGLIST])
|| NILP (args[COMPILED_ARGLIST]))
&& STRINGP (args[COMPILED_BYTECODE])
&& !STRING_MULTIBYTE (args[COMPILED_BYTECODE])
&& VECTORP (args[COMPILED_CONSTANTS])
&& FIXNATP (args[COMPILED_STACK_DEPTH])))
error ("Invalid byte-code object");
/* We used to purecopy everything here, if purify-flag was set. This worked
OK for Emacs-23, but with Emacs-24's lexical binding code, it can be
@ -3474,10 +3463,8 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT
copied into pure space, including its free variables, which is sometimes
just wasteful and other times plainly wrong (e.g. those free vars may want
to be setcar'd). */
memcpy (p->contents, args, nargs * sizeof *args);
make_byte_code (p);
XSETCOMPILED (val, p);
Lisp_Object val = Fvector (nargs, args);
XSETPVECTYPE (XVECTOR (val), PVEC_COMPILED);
return val;
}
@ -5019,8 +5006,9 @@ mark_stack (char const *bottom, char const *end)
#endif
}
/* This is a trampoline function that flushes registers to the stack,
and then calls FUNC. ARG is passed through to FUNC verbatim.
/* flush_stack_call_func is the trampoline function that flushes
registers to the stack, and then calls FUNC. ARG is passed through
to FUNC verbatim.
This function must be called whenever Emacs is about to release the
global interpreter lock. This lets the garbage collector easily
@ -5028,7 +5016,20 @@ mark_stack (char const *bottom, char const *end)
Lisp.
It is invalid to run any Lisp code or to allocate any GC memory
from FUNC. */
from FUNC.
Note: all register spilling is done in flush_stack_call_func before
flush_stack_call_func1 is activated.
flush_stack_call_func1 is responsible for identifying the stack
address range to be scanned. It *must* be carefully kept as
noinline to make sure that registers has been spilled before it is
called, otherwise given __builtin_frame_address (0) typically
returns the frame pointer (base pointer) and not the stack pointer
[1] GC will miss to scan callee-saved registers content
(Bug#41357).
[1] <https://gcc.gnu.org/onlinedocs/gcc/Return-Address.html>. */
NO_INLINE void
flush_stack_call_func1 (void (*func) (void *arg), void *arg)

View file

@ -119,6 +119,7 @@ static void free_buffer_text (struct buffer *b);
static struct Lisp_Overlay * copy_overlays (struct buffer *, struct Lisp_Overlay *);
static void modify_overlay (struct buffer *, ptrdiff_t, ptrdiff_t);
static Lisp_Object buffer_lisp_local_variables (struct buffer *, bool);
static Lisp_Object buffer_local_variables_1 (struct buffer *buf, int offset, Lisp_Object sym);
static void
CHECK_OVERLAY (Lisp_Object x)
@ -1300,6 +1301,25 @@ buffer_lisp_local_variables (struct buffer *buf, bool clone)
return result;
}
/* If the variable at position index OFFSET in buffer BUF has a
buffer-local value, return (name . value). If SYM is non-nil,
it replaces name. */
static Lisp_Object
buffer_local_variables_1 (struct buffer *buf, int offset, Lisp_Object sym)
{
int idx = PER_BUFFER_IDX (offset);
if ((idx == -1 || PER_BUFFER_VALUE_P (buf, idx))
&& SYMBOLP (PER_BUFFER_SYMBOL (offset)))
{
sym = NILP (sym) ? PER_BUFFER_SYMBOL (offset) : sym;
Lisp_Object val = per_buffer_value (buf, offset);
return EQ (val, Qunbound) ? sym : Fcons (sym, val);
}
return Qnil;
}
DEFUN ("buffer-local-variables", Fbuffer_local_variables,
Sbuffer_local_variables, 0, 1, 0,
doc: /* Return an alist of variables that are buffer-local in BUFFER.
@ -1311,25 +1331,25 @@ No argument or nil as argument means use current buffer as BUFFER. */)
{
struct buffer *buf = decode_buffer (buffer);
Lisp_Object result = buffer_lisp_local_variables (buf, 0);
Lisp_Object tem;
/* Add on all the variables stored in special slots. */
{
int offset, idx;
int offset;
FOR_EACH_PER_BUFFER_OBJECT_AT (offset)
{
idx = PER_BUFFER_IDX (offset);
if ((idx == -1 || PER_BUFFER_VALUE_P (buf, idx))
&& SYMBOLP (PER_BUFFER_SYMBOL (offset)))
{
Lisp_Object sym = PER_BUFFER_SYMBOL (offset);
Lisp_Object val = per_buffer_value (buf, offset);
result = Fcons (EQ (val, Qunbound) ? sym : Fcons (sym, val),
result);
}
tem = buffer_local_variables_1 (buf, offset, Qnil);
if (!NILP (tem))
result = Fcons (tem, result);
}
}
tem = buffer_local_variables_1 (buf, PER_BUFFER_VAR_OFFSET (undo_list),
intern ("buffer-undo-list"));
if (!NILP (tem))
result = Fcons (tem, result);
return result;
}

View file

@ -319,6 +319,19 @@ the third, MAXDEPTH, the maximum stack depth used in this function.
If the third argument is incorrect, Emacs may crash. */)
(Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth)
{
if (! (STRINGP (bytestr) && VECTORP (vector) && FIXNATP (maxdepth)))
error ("Invalid byte-code");
if (STRING_MULTIBYTE (bytestr))
{
/* BYTESTR must have been produced by Emacs 20.2 or earlier
because it produced a raw 8-bit string for byte-code and now
such a byte-code string is loaded as multibyte with raw 8-bit
characters converted to multibyte form. Convert them back to
the original unibyte form. */
bytestr = Fstring_as_unibyte (bytestr);
}
return exec_byte_code (bytestr, vector, maxdepth, Qnil, 0, NULL);
}
@ -344,21 +357,10 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
int volatile this_op = 0;
#endif
CHECK_STRING (bytestr);
CHECK_VECTOR (vector);
CHECK_FIXNAT (maxdepth);
eassert (!STRING_MULTIBYTE (bytestr));
ptrdiff_t const_length = ASIZE (vector);
if (STRING_MULTIBYTE (bytestr))
/* BYTESTR must have been produced by Emacs 20.2 or the earlier
because they produced a raw 8-bit string for byte-code and now
such a byte-code string is loaded as multibyte while raw 8-bit
characters converted to multibyte form. Thus, now we must
convert them back to the originally intended unibyte form. */
bytestr = Fstring_as_unibyte (bytestr);
ptrdiff_t bytestr_length = SBYTES (bytestr);
ptrdiff_t bytestr_length = SCHARS (bytestr);
Lisp_Object *vectorp = XVECTOR (vector)->contents;
unsigned char quitcounter = 1;

View file

@ -124,6 +124,11 @@ static const char emacs_version[] = PACKAGE_VERSION;
static const char emacs_copyright[] = COPYRIGHT;
static const char emacs_bugreport[] = PACKAGE_BUGREPORT;
/* Put version info into the executable in the form that 'ident' uses. */
char const EXTERNALLY_VISIBLE RCS_Id[]
= "$Id" ": GNU Emacs " PACKAGE_VERSION
" (" EMACS_CONFIGURATION " " EMACS_CONFIG_FEATURES ") $";
/* Empty lisp strings. To avoid having to build any others. */
Lisp_Object empty_unibyte_string, empty_multibyte_string;

View file

@ -2913,6 +2913,21 @@ funcall_subr (struct Lisp_Subr *subr, ptrdiff_t numargs, Lisp_Object *args)
}
}
/* Call the compiled Lisp function FUN. If we have not yet read FUN's
bytecode string and constants vector, fetch them from the file first. */
static Lisp_Object
fetch_and_exec_byte_code (Lisp_Object fun, Lisp_Object syms_left,
ptrdiff_t nargs, Lisp_Object *args)
{
if (CONSP (AREF (fun, COMPILED_BYTECODE)))
Ffetch_bytecode (fun);
return exec_byte_code (AREF (fun, COMPILED_BYTECODE),
AREF (fun, COMPILED_CONSTANTS),
AREF (fun, COMPILED_STACK_DEPTH),
syms_left, nargs, args);
}
static Lisp_Object
apply_lambda (Lisp_Object fun, Lisp_Object args, ptrdiff_t count)
{
@ -2977,9 +2992,6 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
}
else if (COMPILEDP (fun))
{
ptrdiff_t size = PVSIZE (fun);
if (size <= COMPILED_STACK_DEPTH)
xsignal1 (Qinvalid_function, fun);
syms_left = AREF (fun, COMPILED_ARGLIST);
if (FIXNUMP (syms_left))
/* A byte-code object with an integer args template means we
@ -2991,15 +3003,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
argument-binding code below instead (as do all interpreted
functions, even lexically bound ones). */
{
/* If we have not actually read the bytecode string
and constants vector yet, fetch them from the file. */
if (CONSP (AREF (fun, COMPILED_BYTECODE)))
Ffetch_bytecode (fun);
return exec_byte_code (AREF (fun, COMPILED_BYTECODE),
AREF (fun, COMPILED_CONSTANTS),
AREF (fun, COMPILED_STACK_DEPTH),
syms_left,
nargs, arg_vector);
return fetch_and_exec_byte_code (fun, syms_left, nargs, arg_vector);
}
lexenv = Qnil;
}
@ -3068,16 +3072,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
if (CONSP (fun))
val = Fprogn (XCDR (XCDR (fun)));
else
{
/* If we have not actually read the bytecode string
and constants vector yet, fetch them from the file. */
if (CONSP (AREF (fun, COMPILED_BYTECODE)))
Ffetch_bytecode (fun);
val = exec_byte_code (AREF (fun, COMPILED_BYTECODE),
AREF (fun, COMPILED_CONSTANTS),
AREF (fun, COMPILED_STACK_DEPTH),
Qnil, 0, 0);
}
val = fetch_and_exec_byte_code (fun, Qnil, 0, NULL);
return unbind_to (count, val);
}
@ -3162,9 +3157,6 @@ lambda_arity (Lisp_Object fun)
}
else if (COMPILEDP (fun))
{
ptrdiff_t size = PVSIZE (fun);
if (size <= COMPILED_STACK_DEPTH)
xsignal1 (Qinvalid_function, fun);
syms_left = AREF (fun, COMPILED_ARGLIST);
if (FIXNUMP (syms_left))
return get_byte_code_arity (syms_left);
@ -3207,13 +3199,11 @@ DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
if (COMPILEDP (object))
{
ptrdiff_t size = PVSIZE (object);
if (size <= COMPILED_STACK_DEPTH)
xsignal1 (Qinvalid_function, object);
if (CONSP (AREF (object, COMPILED_BYTECODE)))
{
tem = read_doc_string (AREF (object, COMPILED_BYTECODE));
if (!CONSP (tem))
if (! (CONSP (tem) && STRINGP (XCAR (tem))
&& VECTORP (XCDR (tem))))
{
tem = AREF (object, COMPILED_BYTECODE);
if (CONSP (tem) && STRINGP (XCAR (tem)))
@ -3221,7 +3211,19 @@ DEFUN ("fetch-bytecode", Ffetch_bytecode, Sfetch_bytecode,
else
error ("Invalid byte code");
}
ASET (object, COMPILED_BYTECODE, XCAR (tem));
Lisp_Object bytecode = XCAR (tem);
if (STRING_MULTIBYTE (bytecode))
{
/* BYTECODE must have been produced by Emacs 20.2 or earlier
because it produced a raw 8-bit string for byte-code and now
such a byte-code string is loaded as multibyte with raw 8-bit
characters converted to multibyte form. Convert them back to
the original unibyte form. */
bytecode = Fstring_as_unibyte (bytecode);
}
ASET (object, COMPILED_BYTECODE, bytecode);
ASET (object, COMPILED_CONSTANTS, XCDR (tem));
}
}

View file

@ -2508,26 +2508,36 @@ ARRAY is a vector, string, char-table, or bool-vector. */)
}
else if (STRINGP (array))
{
register unsigned char *p = SDATA (array);
int charval;
unsigned char *p = SDATA (array);
CHECK_CHARACTER (item);
charval = XFIXNAT (item);
int charval = XFIXNAT (item);
size = SCHARS (array);
if (STRING_MULTIBYTE (array))
if (size != 0)
{
CHECK_IMPURE (array, XSTRING (array));
unsigned char str[MAX_MULTIBYTE_LENGTH];
int len = CHAR_STRING (charval, str);
ptrdiff_t size_byte = SBYTES (array);
ptrdiff_t product;
int len;
if (STRING_MULTIBYTE (array))
len = CHAR_STRING (charval, str);
else
{
str[0] = charval;
len = 1;
}
if (INT_MULTIPLY_WRAPV (size, len, &product) || product != size_byte)
error ("Attempt to change byte length of a string");
for (idx = 0; idx < size_byte; idx++)
*p++ = str[idx % len];
ptrdiff_t size_byte = SBYTES (array);
if (len == 1 && size == size_byte)
memset (p, str[0], size);
else
{
ptrdiff_t product;
if (INT_MULTIPLY_WRAPV (size, len, &product)
|| product != size_byte)
error ("Attempt to change byte length of a string");
for (idx = 0; idx < size_byte; idx++)
*p++ = str[idx % len];
}
}
else
for (idx = 0; idx < size; idx++)
p[idx] = charval;
}
else if (BOOL_VECTOR_P (array))
return bool_vector_fill (array, item);
@ -2542,12 +2552,15 @@ DEFUN ("clear-string", Fclear_string, Sclear_string,
This makes STRING unibyte and may change its length. */)
(Lisp_Object string)
{
ptrdiff_t len;
CHECK_STRING (string);
len = SBYTES (string);
memset (SDATA (string), 0, len);
STRING_SET_CHARS (string, len);
STRING_SET_UNIBYTE (string);
ptrdiff_t len = SBYTES (string);
if (len != 0 || STRING_MULTIBYTE (string))
{
CHECK_IMPURE (string, XSTRING (string));
memset (SDATA (string), 0, len);
STRING_SET_CHARS (string, len);
STRING_SET_UNIBYTE (string);
}
return Qnil;
}

View file

@ -1343,7 +1343,6 @@ dead_object (void)
#define XSETWINDOW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_WINDOW))
#define XSETTERMINAL(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_TERMINAL))
#define XSETSUBR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUBR))
#define XSETCOMPILED(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_COMPILED))
#define XSETBUFFER(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BUFFER))
#define XSETCHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_CHAR_TABLE))
#define XSETBOOL_VECTOR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BOOL_VECTOR))
@ -3943,7 +3942,6 @@ build_string (const char *str)
extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
extern void make_byte_code (struct Lisp_Vector *);
extern struct Lisp_Vector *allocate_vector (ptrdiff_t);
extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);

View file

@ -3030,8 +3030,26 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
struct Lisp_Vector *vec;
tmp = read_vector (readcharfun, 1);
vec = XVECTOR (tmp);
if (vec->header.size == 0)
invalid_syntax ("Empty byte-code object");
if (! (COMPILED_STACK_DEPTH < vec->header.size
&& (FIXNUMP (vec->contents[COMPILED_ARGLIST])
|| CONSP (vec->contents[COMPILED_ARGLIST])
|| NILP (vec->contents[COMPILED_ARGLIST]))
&& ((STRINGP (vec->contents[COMPILED_BYTECODE])
&& VECTORP (vec->contents[COMPILED_CONSTANTS]))
|| CONSP (vec->contents[COMPILED_BYTECODE]))
&& FIXNATP (vec->contents[COMPILED_STACK_DEPTH])))
invalid_syntax ("Invalid byte-code object");
if (STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE)))
{
/* BYTESTR must have been produced by Emacs 20.2 or earlier
because it produced a raw 8-bit string for byte-code and
now such a byte-code string is loaded as multibyte with
raw 8-bit characters converted to multibyte form.
Convert them back to the original unibyte form. */
ASET (tmp, COMPILED_BYTECODE,
Fstring_as_unibyte (AREF (tmp, COMPILED_BYTECODE)));
}
if (COMPILED_DOC_STRING < vec->header.size
&& EQ (AREF (tmp, COMPILED_DOC_STRING), make_fixnum (0)))
@ -3050,7 +3068,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
ASET (tmp, COMPILED_DOC_STRING, make_ufixnum (hash));
}
make_byte_code (vec);
XSETPVECTYPE (vec, PVEC_COMPILED);
return tmp;
}
if (c == '(')
@ -3888,8 +3906,6 @@ read_vector (Lisp_Object readcharfun, bool bytecodeflag)
{
Lisp_Object tem = read_list (1, readcharfun);
ptrdiff_t size = list_length (tem);
if (bytecodeflag && size <= COMPILED_STACK_DEPTH)
error ("Invalid byte code");
Lisp_Object vector = make_nil_vector (size);
Lisp_Object *ptr = XVECTOR (vector)->contents;

View file

@ -6519,7 +6519,15 @@ acl_get_file (const char *fname, acl_type_t type)
if (!get_file_security (fname, si, psd, sd_len, &sd_len))
{
xfree (psd);
errno = EIO;
err = GetLastError ();
if (err == ERROR_NOT_SUPPORTED)
errno = ENOTSUP;
else if (err == ERROR_FILE_NOT_FOUND
|| err == ERROR_PATH_NOT_FOUND
|| err == ERROR_INVALID_NAME)
errno = ENOENT;
else
errno = EIO;
psd = NULL;
}
}
@ -6530,6 +6538,8 @@ acl_get_file (const char *fname, acl_type_t type)
be encoded in the current ANSI codepage. */
|| err == ERROR_INVALID_NAME)
errno = ENOENT;
else if (err == ERROR_NOT_SUPPORTED)
errno = ENOTSUP;
else
errno = EIO;
}

View file

@ -546,6 +546,24 @@ baz\"\""
(electric-pair-delete-pair 1)
(should (equal "" (buffer-string))))))
;;; Undoing
(ert-deftest electric-pair-undo-unrelated-state ()
"Make sure `electric-pair-mode' does not confuse `undo' (bug#39680)."
(with-temp-buffer
(buffer-enable-undo)
(electric-pair-local-mode)
(let ((last-command-event ?\())
(ert-simulate-command '(self-insert-command 1)))
(undo-boundary)
(let ((last-command-event ?a))
(ert-simulate-command '(self-insert-command 1)))
(undo-boundary)
(ert-simulate-command '(undo))
(let ((last-command-event ?\())
(ert-simulate-command '(self-insert-command 1)))
(should (string= (buffer-string) "(())"))))
;;; Electric newlines between pairs
;;; TODO: better tests

View file

@ -0,0 +1,67 @@
;;; syntax-tests.el --- tests for syntax.el -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
(require 'ert)
(require 'syntax)
(ert-deftest syntax-propertize--shift-groups-and-backrefs ()
"Test shifting of numbered groups and back-references in regexps."
;; A numbered group must be shifted.
(should
(string=
(syntax-propertize--shift-groups-and-backrefs
"\\(?2:[abc]+\\)foobar" 2)
"\\(?4:[abc]+\\)foobar"))
;; A back-reference \1 on a normal sub-regexp context must be
;; shifted.
(should
(string=
(syntax-propertize--shift-groups-and-backrefs "\\(a\\)\\1" 2)
"\\(a\\)\\3"))
;; Shifting must not happen if the \1 appears in a character class,
;; or in a \{\} repetition construct (although \1 isn't valid there
;; anyway).
(let ((rx-with-class "\\(a\\)[\\1-2]")
(rx-with-rep "\\(a\\)\\{1,\\1\\}"))
(should
(string=
(syntax-propertize--shift-groups-and-backrefs rx-with-class 2)
rx-with-class))
(should
(string=
(syntax-propertize--shift-groups-and-backrefs rx-with-rep 2)
rx-with-rep)))
;; Now numbered groups and back-references in combination.
(should
(string=
(syntax-propertize--shift-groups-and-backrefs
"\\(?2:[abc]+\\)foo\\(\\2\\)" 2)
"\\(?4:[abc]+\\)foo\\(\\4\\)"))
;; Emacs supports only the back-references \1,...,\9, so when a
;; shift would result in \10 or more, an error must be signalled.
(should-error
(syntax-propertize--shift-groups-and-backrefs "\\(a\\)\\3" 7)))
;; Local Variables:
;; no-byte-compile: t
;; End:
;;; syntax-tests.el ends here.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,73 @@
;;; webjump-tests.el --- Tests for webjump.el -*- lexical-binding: t; -*-
;; Copyright (C) 2020 Free Software Foundation, Inc.
;; Author: Simen Heggestøyl <simenheg@gmail.com>
;; Keywords:
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(require 'ert)
(require 'webjump)
(ert-deftest webjump-tests-builtin ()
(should (equal (webjump-builtin '[name] "gnu.org") "gnu.org")))
(ert-deftest webjump-tests-builtin-check-args ()
(should (webjump-builtin-check-args [1 2 3] "Foo" 2))
(should-error (webjump-builtin-check-args [1 2 3] "Foo" 3)))
(ert-deftest webjump-tests-mirror-default ()
(should (equal (webjump-mirror-default
'("https://ftp.gnu.org/pub/gnu/"
"https://ftpmirror.gnu.org"))
"https://ftp.gnu.org/pub/gnu/")))
(ert-deftest webjump-tests-null-or-blank-string-p ()
(should (webjump-null-or-blank-string-p nil))
(should (webjump-null-or-blank-string-p ""))
(should (webjump-null-or-blank-string-p " "))
(should-not (webjump-null-or-blank-string-p " . ")))
(ert-deftest webjump-tests-url-encode ()
(should (equal (webjump-url-encode "") ""))
(should (equal (webjump-url-encode "a b c") "a+b+c"))
(should (equal (webjump-url-encode "foo?") "foo%3F"))
(should (equal (webjump-url-encode "/foo\\") "/foo%5C"))
(should (equal (webjump-url-encode "f&o") "f%26o")))
(ert-deftest webjump-tests-url-fix ()
(should (equal (webjump-url-fix nil) ""))
(should (equal (webjump-url-fix "/tmp/") "file:///tmp/"))
(should (equal (webjump-url-fix "gnu.org") "http://gnu.org/"))
(should (equal (webjump-url-fix "ftp.x.org") "ftp://ftp.x.org/"))
(should (equal (webjump-url-fix "https://gnu.org")
"https://gnu.org/")))
(ert-deftest webjump-tests-url-fix-trailing-slash ()
(should (equal (webjump-url-fix-trailing-slash "https://gnu.org")
"https://gnu.org/"))
(should (equal (webjump-url-fix-trailing-slash "https://gnu.org/")
"https://gnu.org/")))
(provide 'webjump-tests)
;;; webjump-tests.el ends here

View file

@ -164,6 +164,16 @@ Parser is called with and without 'symbol-qnames argument.")
(should (equal (cdr xml-parse-test--namespace-attribute-qnames)
(xml-parse-region nil nil nil nil 'symbol-qnames)))))
(ert-deftest xml-print-invalid-cdata ()
"Check that Bug#41094 is fixed."
(with-temp-buffer
(should (equal (should-error (xml-print '((foo () "\0")))
:type 'xml-invalid-character)
'(xml-invalid-character 0 1)))
(should (equal (should-error (xml-print '((foo () "\u00FF \xFF")))
:type 'xml-invalid-character)
'(xml-invalid-character #x3FFFFF 3)))))
;; Local Variables:
;; no-byte-compile: t
;; End:

View file

@ -1327,4 +1327,10 @@ with parameters from the *Messages* buffer modification."
(set-buffer-multibyte t)
(buffer-string)))))))
;; https://debbugs.gnu.org/33492
(ert-deftest buffer-tests-buffer-local-variables-undo ()
"Test that `buffer-undo-list' appears in `buffer-local-variables'."
(with-temp-buffer
(should (assq 'buffer-undo-list (buffer-local-variables)))))
;;; buffer-tests.el ends here