summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2022-05-09 18:51:10 -0700
committerSean Whitton <spwhitton@spwhitton.name>2022-05-09 18:51:10 -0700
commita50ea74ec1518a9a506454e015641bf9c94ee3e4 (patch)
tree71c0fa21a7d249cd4d6865000058935c2f1d80e3
parent9a23632f13fd116750f290e07f633cbdf8f2a78c (diff)
parent054062060e9f57fd037578378c23ad9ec294edac (diff)
downloademacs-a50ea74ec1518a9a506454e015641bf9c94ee3e4.tar.gz
Merge remote-tracking branch 'origin/master' into athena/unstable
-rw-r--r--admin/MAINTAINERS8
-rw-r--r--doc/emacs/abbrevs.texi5
-rw-r--r--doc/emacs/maintaining.texi9
-rw-r--r--doc/emacs/mini.texi46
-rw-r--r--doc/emacs/package.texi10
-rw-r--r--doc/emacs/search.texi63
-rw-r--r--doc/lispref/buffers.texi14
-rw-r--r--doc/lispref/display.texi5
-rw-r--r--doc/lispref/help.texi4
-rw-r--r--doc/lispref/modes.texi10
-rw-r--r--doc/lispref/os.texi8
-rw-r--r--doc/lispref/processes.texi14
-rw-r--r--doc/lispref/searching.texi37
-rw-r--r--doc/lispref/windows.texi8
-rw-r--r--etc/HELLO4
-rw-r--r--etc/NEWS120
-rw-r--r--etc/PROBLEMS27
-rw-r--r--etc/tutorials/TUTORIAL.el_GR1267
-rw-r--r--etc/tutorials/TUTORIAL.translators4
-rw-r--r--lib/cdefs.h12
-rw-r--r--lib/libc-config.h11
-rw-r--r--lib/md5.h3
-rw-r--r--lib/regcomp.c16
-rw-r--r--lib/sha1.h3
-rw-r--r--lib/sha256.h3
-rw-r--r--lib/sha512.h3
-rw-r--r--lib/stdlib.in.h4
-rw-r--r--lib/string.in.h4
-rw-r--r--lisp/cus-start.el3
-rw-r--r--lisp/dabbrev.el52
-rw-r--r--lisp/dired-aux.el5
-rw-r--r--lisp/emacs-lisp/easy-mmode.el1
-rw-r--r--lisp/emacs-lisp/eldoc.el19
-rw-r--r--lisp/emacs-lisp/lisp.el2
-rw-r--r--lisp/emacs-lisp/oclosure.el2
-rw-r--r--lisp/emacs-lisp/package.el31
-rw-r--r--lisp/emacs-lisp/shortdoc.el10
-rw-r--r--lisp/emacs-lisp/smie.el4
-rw-r--r--lisp/faces.el14
-rw-r--r--lisp/gnus/gnus-search.el6
-rw-r--r--lisp/gnus/nnvirtual.el11
-rw-r--r--lisp/help-fns.el3
-rw-r--r--lisp/help-mode.el46
-rw-r--r--lisp/icomplete.el65
-rw-r--r--lisp/image-mode.el26
-rw-r--r--lisp/info.el4
-rw-r--r--lisp/international/fontset.el7
-rw-r--r--lisp/isearch.el17
-rw-r--r--lisp/language/greek.el4
-rw-r--r--lisp/language/indian.el116
-rw-r--r--lisp/ldefs-boot.el80
-rw-r--r--lisp/leim/quail/indian.el327
-rw-r--r--lisp/net/browse-url.el20
-rw-r--r--lisp/net/tramp-sh.el49
-rw-r--r--lisp/net/tramp-smb.el6
-rw-r--r--lisp/net/tramp.el84
-rw-r--r--lisp/outline.el4
-rw-r--r--lisp/pixel-scroll.el6
-rw-r--r--lisp/progmodes/cc-engine.el6
-rw-r--r--lisp/progmodes/compile.el5
-rw-r--r--lisp/progmodes/elisp-mode.el21
-rw-r--r--lisp/progmodes/python.el5
-rw-r--r--lisp/server.el2
-rw-r--r--lisp/simple.el20
-rw-r--r--lisp/startup.el20
-rw-r--r--lisp/subr.el38
-rw-r--r--lisp/term.el31
-rw-r--r--lisp/term/haiku-win.el1
-rw-r--r--lisp/term/linux.el4
-rw-r--r--lisp/textmodes/pixel-fill.el4
-rw-r--r--lisp/textmodes/remember.el2
-rw-r--r--lisp/textmodes/table.el17
-rw-r--r--lisp/textmodes/word-wrap-mode.el25
-rw-r--r--lisp/vc/ediff-util.el8
-rw-r--r--lisp/vc/log-view.el16
-rw-r--r--lisp/vc/vc-cvs.el9
-rw-r--r--lisp/vc/vc-rcs.el9
-rw-r--r--lisp/vc/vc-sccs.el9
-rw-r--r--lisp/window.el28
-rw-r--r--lisp/x-dnd.el2
-rw-r--r--lwlib/lwlib.c12
-rw-r--r--src/buffer.c82
-rw-r--r--src/dispextern.h3
-rw-r--r--src/dispnew.c51
-rw-r--r--src/fileio.c25
-rw-r--r--src/fns.c15
-rw-r--r--src/haiku_draw_support.cc46
-rw-r--r--src/haiku_support.cc326
-rw-r--r--src/haiku_support.h11
-rw-r--r--src/haikufns.c25
-rw-r--r--src/haikufont.c13
-rw-r--r--src/haikuselect.c88
-rw-r--r--src/haikuterm.c345
-rw-r--r--src/haikuterm.h9
-rw-r--r--src/image.c132
-rw-r--r--src/keyboard.c18
-rw-r--r--src/keyboard.h9
-rw-r--r--src/nsmenu.m22
-rw-r--r--src/nsterm.m4
-rw-r--r--src/pgtkterm.c23
-rw-r--r--src/process.c18
-rw-r--r--src/termhooks.h5
-rw-r--r--src/w32fns.c21
-rw-r--r--src/w32notify.c4
-rw-r--r--src/window.c34
-rw-r--r--src/window.h4
-rw-r--r--src/xdisp.c17
-rw-r--r--src/xfns.c59
-rw-r--r--src/xmenu.c116
-rw-r--r--src/xterm.c510
-rw-r--r--src/xterm.h15
-rw-r--r--test/lisp/emacs-lisp/easy-mmode-tests.el2
-rw-r--r--test/lisp/help-mode-tests.el2
-rw-r--r--test/lisp/net/tramp-tests.el106
-rw-r--r--test/lisp/subr-tests.el16
-rw-r--r--test/src/buffer-tests.el35
-rw-r--r--test/src/image-tests.el7
117 files changed, 4338 insertions, 920 deletions
diff --git a/admin/MAINTAINERS b/admin/MAINTAINERS
index 092978f6d2c..2760a9a42b5 100644
--- a/admin/MAINTAINERS
+++ b/admin/MAINTAINERS
@@ -275,14 +275,6 @@ Vibhav Pant
lisp/net/browse-url.el
lisp/erc/*
-Alan Third
- The NS port:
- nextstep/*
- src/ns*
- src/*.m
- lisp/term/ns-win.el
- doc/emacs/macos.texi
-
Amin Bandali
Eshell
lisp/eshell/*
diff --git a/doc/emacs/abbrevs.texi b/doc/emacs/abbrevs.texi
index 9f339a03577..07f66ec10ac 100644
--- a/doc/emacs/abbrevs.texi
+++ b/doc/emacs/abbrevs.texi
@@ -411,10 +411,13 @@ away in the buffer to search for an expansion.
@vindex dabbrev-check-all-buffers
@vindex dabbrev-check-other-buffers
+@vindex dabbrev-ignored-buffer-modes
After scanning the current buffer, @kbd{M-/} normally searches other
buffers. The variables @code{dabbrev-check-all-buffers} and
@code{dabbrev-check-other-buffers} can be used to determine which
-other buffers, if any, are searched.
+other buffers, if any, are searched. Buffers that have major modes
+derived from any of the modes in @code{dabbrev-ignored-buffer-modes}
+are ignored.
@vindex dabbrev-ignored-buffer-names
@vindex dabbrev-ignored-buffer-regexps
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index fc2b2a24e2c..cca8441daa5 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -1055,15 +1055,6 @@ prefix argument is a repeat count.
Move to the next revision entry. A numeric prefix argument is a
repeat count.
-@item P
-Move to the log of the previous file, if showing logs for a multi-file
-VC fileset. Otherwise, just move to the beginning of the log. A
-numeric prefix argument is a repeat count.
-
-@item N
-Move to the log of the next file, if showing logs for a multi-file VC
-fileset. A numeric prefix argument is a repeat count.
-
@item a
Annotate the revision on the current line (@pxref{Old Revisions}).
diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi
index a899fea7e39..4e71793b66e 100644
--- a/doc/emacs/mini.texi
+++ b/doc/emacs/mini.texi
@@ -381,16 +381,16 @@ used with the completion list:
@vindex minibuffer-completion-auto-choose
@item M-@key{DOWN}
@itemx M-@key{UP}
-These keys will navigate through the completions displayed in the
-completions buffer. When @code{minibuffer-completion-auto-choose} is
-non-@code{nil} (which is the default), using these commands will
-automatically insert the current completion candidate in the
-minibuffer. If this user option is @code{nil}, the keys will navigate
-the same way as before, but won't automatically insert the candidate
-in the minibuffer. Instead you have to use the @kbd{M-@key{RET}} command to
-do that. With a prefix argument, @kbd{C-u M-@key{RET}} inserts the
-currently active candidate to the minibuffer, but doesn't exit the
-minibuffer.
+While in the minibuffer, these keys navigate through the completions
+displayed in the completions buffer. When
+@code{minibuffer-completion-auto-choose} is non-@code{nil} (which is
+the default), using these commands also inserts the current completion
+candidate into the minibuffer. If
+@code{minibuffer-completion-auto-choose} is @code{nil}, you can use
+the @kbd{M-@key{RET}} command to insert the completion candidates into
+the minibuffer. By default, that exits the minibuffer, but with a
+prefix argument, @kbd{C-u M-@key{RET}} inserts the currently active
+candidate without exiting the minibuffer.
@findex switch-to-completions
@item M-v
@@ -407,7 +407,10 @@ ways (@pxref{Windows}).
@itemx mouse-1
@itemx mouse-2
While in the completion list buffer, this chooses the completion at
-point (@code{choose-completion}).
+point (@code{choose-completion}). With a prefix argument, @kbd{C-u
+@key{RET}} inserts the completion at point into the minibuffer, but
+doesn't exit the minibuffer---thus, you can change your mind and
+choose another candidate.
@findex next-completion
@item @key{TAB}
@@ -682,17 +685,20 @@ behavior only when there are @var{n} or fewer alternatives.
@vindex completions-format
When displaying completions, Emacs will normally pop up a new buffer
-to display the completions. The completions will (by default) be
-sorted in columns horizontally in alphabetical order, but this can be
-changed by changing the @code{completions-format} user option. If
-@code{vertical}, sort the completions vertically in columns instead,
-and if @code{one-column}, just use a single column.
+to display the completions. The completions will by default be sorted
+horizontally, using as many columns as will fit in the window-width,
+but this can be changed by customizing the @code{completions-format}
+user option. If its value is @code{vertical}, Emacs will sort the
+completions vertically instead, and if it's @code{one-column}, Emacs
+will use just one column.
@vindex completions-sort
- This user option controls how completions are sorted in the
-@samp{*Completions*} buffer. The default is @code{alphabetical}, but
-it can also be a function which will be called with the list of
-completions, and should return the list in the desired order.
+ The @code{completions-sort} user option controls the order in which
+the completions are sorted in the @samp{*Completions*} buffer. The
+default is @code{alphabetical}, which sorts in alphabetical order.
+The value @code{nil} disables sorting. The value can also be a
+function, which will be called with the list of completions, and
+should return the list in the desired order.
@vindex completions-max-height
When @code{completions-max-height} is non-@code{nil}, it limits the
diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi
index bd3ae2aa6ad..fc2a093ec42 100644
--- a/doc/emacs/package.texi
+++ b/doc/emacs/package.texi
@@ -89,6 +89,11 @@ list of available packages from package archive servers. If the
network is unavailable, it falls back on the most recently retrieved
list.
+The main command to use in the package list buffer is the @key{x}
+command. If the package under point isn't installed already, this
+command will install it. If the package under point is already
+installed, this command will delete it.
+
The following commands are available in the package menu:
@table @kbd
@@ -162,7 +167,10 @@ installed versions (marked with status @samp{obsolete}).
@findex package-menu-execute
Download and install all packages marked with @kbd{i}, and their
dependencies; also, delete all packages marked with @kbd{d}
-(@code{package-menu-execute}). This also removes the marks.
+(@code{package-menu-execute}). This also removes the marks. If no
+packages are marked, this command will install the package under point
+(if it isn't installed already), or delete the package under point (if
+it's already installed).
@item g
@item r
diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi
index c990f5d766a..b123ef83a16 100644
--- a/doc/emacs/search.texi
+++ b/doc/emacs/search.texi
@@ -1027,24 +1027,11 @@ you search for @samp{a.*?$} against the text @samp{abbab} followed by
a newline, it matches the whole string. Since it @emph{can} match
starting at the first @samp{a}, it does.
-@item @kbd{\@{@var{n}\@}}
-is a postfix operator specifying @var{n} repetitions---that is, the
-preceding regular expression must match exactly @var{n} times in a
-row. For example, @samp{x\@{4\@}} matches the string @samp{xxxx} and
-nothing else.
-
-@item @kbd{\@{@var{n},@var{m}\@}}
-is a postfix operator specifying between @var{n} and @var{m}
-repetitions---that is, the preceding regular expression must match at
-least @var{n} times, but no more than @var{m} times. If @var{m} is
-omitted, then there is no upper limit, but the preceding regular
-expression must match at least @var{n} times.@* @samp{\@{0,1\@}} is
-equivalent to @samp{?}. @* @samp{\@{0,\@}} is equivalent to
-@samp{*}. @* @samp{\@{1,\@}} is equivalent to @samp{+}.
-
+@cindex set of alternative characters, in regular expressions
+@cindex character set, in regular expressions
@item @kbd{[ @dots{} ]}
-is a @dfn{character set}, beginning with @samp{[} and terminated by
-@samp{]}.
+is a @dfn{set of alternative characters}, or a @dfn{character set},
+beginning with @samp{[} and terminated by @samp{]}.
In the simplest case, the characters between the two brackets are what
this set can match. Thus, @samp{[ad]} matches either one @samp{a} or
@@ -1061,9 +1048,10 @@ which matches any lower-case @acronym{ASCII} letter or @samp{$}, @samp{%} or
period. As another example, @samp{[α-ωί]} matches all lower-case
Greek letters.
+@cindex character classes, in regular expressions
You can also include certain special @dfn{character classes} in a
character set. A @samp{[:} and balancing @samp{:]} enclose a
-character class inside a character alternative. For instance,
+character class inside a set of alternative characters. For instance,
@samp{[[:alnum:]]} matches any letter or digit. @xref{Char Classes,,,
elisp, The Emacs Lisp Reference Manual}, for a list of character
classes.
@@ -1131,13 +1119,13 @@ no preceding expression on which the @samp{*} can act. It is poor practice
to depend on this behavior; it is better to quote the special character anyway,
regardless of where it appears.
-As a @samp{\} is not special inside a character alternative, it can
-never remove the special meaning of @samp{-} or @samp{]}. So you
-should not quote these characters when they have no special meaning
-either. This would not clarify anything, since backslashes can
-legitimately precede these characters where they @emph{have} special
-meaning, as in @samp{[^\]} (@code{"[^\\]"} for Lisp string syntax),
-which matches any single character except a backslash.
+As a @samp{\} is not special inside a set of alternative characters, it can
+never remove the special meaning of @samp{-}, @samp{^} or @samp{]}.
+You should not quote these characters when they have no special
+meaning. This would not clarify anything, since backslashes
+can legitimately precede these characters where they @emph{have}
+special meaning, as in @samp{[^\]} (@code{"[^\\]"} for Lisp string
+syntax), which matches any single character except a backslash.
@node Regexp Backslash
@section Backslash in Regular Expressions
@@ -1202,11 +1190,11 @@ matches the same text that matched the @var{d}th occurrence of a
@samp{\( @dots{} \)} construct. This is called a @dfn{back
reference}.
-After the end of a @samp{\( @dots{} \)} construct, the matcher remembers
-the beginning and end of the text matched by that construct. Then,
-later on in the regular expression, you can use @samp{\} followed by the
-digit @var{d} to mean ``match the same text matched the @var{d}th time
-by the @samp{\( @dots{} \)} construct''.
+After the end of a @samp{\( @dots{} \)} construct, the matcher
+remembers the beginning and end of the text matched by that construct.
+Then, later on in the regular expression, you can use @samp{\}
+followed by the digit @var{d} to mean ``match the same text matched
+the @var{d}th @samp{\( @dots{} \)} construct''.
The strings matching the first nine @samp{\( @dots{} \)} constructs
appearing in a regular expression are assigned numbers 1 through 9 in
@@ -1223,6 +1211,21 @@ If a particular @samp{\( @dots{} \)} construct matches more than once
(which can easily happen if it is followed by @samp{*}), only the last
match is recorded.
+@item @kbd{\@{@var{m}\@}}
+is a postfix operator specifying @var{m} repetitions---that is, the
+preceding regular expression must match exactly @var{m} times in a
+row. For example, @samp{x\@{4\@}} matches the string @samp{xxxx} and
+nothing else.
+
+@item @kbd{\@{@var{m},@var{n}\@}}
+is a postfix operator specifying between @var{m} and @var{n}
+repetitions---that is, the preceding regular expression must match at
+least @var{m} times, but no more than @var{n} times. If @var{n} is
+omitted, then there is no upper limit, but the preceding regular
+expression must match at least @var{m} times.@* @samp{\@{0,1\@}} is
+equivalent to @samp{?}. @* @samp{\@{0,\@}} is equivalent to
+@samp{*}. @* @samp{\@{1,\@}} is equivalent to @samp{+}.
+
@item \`
matches the empty string, but only at the beginning of the string or
buffer (or its accessible portion) being matched against.
diff --git a/doc/lispref/buffers.texi b/doc/lispref/buffers.texi
index d8cf3d7919b..8d1d9f5ddb2 100644
--- a/doc/lispref/buffers.texi
+++ b/doc/lispref/buffers.texi
@@ -541,10 +541,12 @@ file formerly visited.
@ref{Text}.
@defun buffer-modified-p &optional buffer
-This function returns @code{t} if the buffer @var{buffer} has been modified
-since it was last read in from a file or saved, or @code{nil}
-otherwise. If @var{buffer} is not supplied, the current buffer
-is tested.
+This function returns non-@code{nil} if the buffer @var{buffer} has
+been modified since it was last read in from a file or saved, or
+@code{nil} otherwise. If @var{buffer} has been autosaved after
+@var{buffer} was last modified, the symbol @code{autosaved} is
+returned. If @var{buffer} is not supplied, the current buffer is
+tested.
@end defun
@defun set-buffer-modified-p flag
@@ -564,7 +566,9 @@ function @code{force-mode-line-update} works by doing this:
@defun restore-buffer-modified-p flag
Like @code{set-buffer-modified-p}, but does not force redisplay
-of mode lines.
+of mode lines. This function also allows a @var{flag} value of
+@code{autosaved}, which marks the buffer as having been autosaved
+after the last modification.
@end defun
@deffn Command not-modified &optional arg
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 390d1650253..9650d227909 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -4021,7 +4021,10 @@ required; and @code{gpos} is a list of OpenType GPOS feature tag
symbols, or @code{nil} if none is required. If @code{gsub} or
@code{gpos} is a list, a @code{nil} element in that list means that
the font must not match any of the remaining tag symbols. The
-@code{gpos} element may be omitted.
+@code{gpos} element may be omitted. For the list of OpenType script,
+language, and feature tags, see
+@uref{https://docs.microsoft.com/en-us/typography/opentype/spec/ttoreg,
+the list of registered OTF tags}.
@item :type
@cindex font backend
diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi
index d53bfad8e9e..f029a1c97cc 100644
--- a/doc/lispref/help.texi
+++ b/doc/lispref/help.texi
@@ -362,6 +362,10 @@ depending on the value of @code{text-quoting-style}.
quotes the following character and is discarded; thus, @samp{\=`} puts
@samp{`} into the output, @samp{\=\[} puts @samp{\[} into the output,
and @samp{\=\=} puts @samp{\=} into the output.
+
+@item \+
+This indicates that the symbol directly following should not be marked
+as link in the @file{*Help*} buffer.
@end table
@strong{Please note:} Each @samp{\} must be doubled when written in a
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index ff09a787490..a0c1c488fe7 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -1912,6 +1912,16 @@ This means ``use in modes derived from @code{text-mode}, but nowhere
else''. (There's an implicit @code{nil} element at the end.)
@end defmac
+@findex buffer-local-restore-state
+@defmac buffer-local-set-state variable value...
+Minor modes often set buffer-local variables that affect some features
+in Emacs. When a minor mode is switched off, the mode is expected to
+restore the previous state of these variables. This convenience macro
+helps with doing that: It works much like @code{setq-local}, but
+returns an object that can be used to restore these values back to
+their previous values/states (using the companion function
+@code{buffer-local-restore-state}).
+@end defmac
@node Mode Line Format
@section Mode Line Format
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 9df708532d8..f4dd2e70723 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -329,10 +329,10 @@ file will not inhibit the message for someone else.
@end defopt
@defopt initial-scratch-message
-This variable, if non-@code{nil}, should be a string, which is
-treated as documentation to be
-inserted into the @file{*scratch*} buffer when Emacs starts up. If it
-is @code{nil}, the @file{*scratch*} buffer is empty.
+This variable, if non-@code{nil}, should be a string, which is treated
+as documentation to be inserted into the @file{*scratch*} buffer when
+Emacs starts up or when that buffer is recreated. If it is
+@code{nil}, the @file{*scratch*} buffer is empty.
@end defopt
@noindent
diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
index 18f446735bb..668a577870a 100644
--- a/doc/lispref/processes.texi
+++ b/doc/lispref/processes.texi
@@ -1011,16 +1011,18 @@ terminated (due to calling @code{exit} or to a signal). If it is
they exit.
@end defopt
-@defun delete-process process
+@defun delete-process &optional process
This function deletes a process, killing it with a @code{SIGKILL}
signal if the process was running a program. The argument may be a
process, the name of a process, a buffer, or the name of a buffer. (A
buffer or buffer-name stands for the process that
-@code{get-buffer-process} returns.) Calling @code{delete-process} on
-a running process terminates it, updates the process status, and runs
-the sentinel immediately. If the process has already terminated,
-calling @code{delete-process} has no effect on its status, or on the
-running of its sentinel (which will happen sooner or later).
+@code{get-buffer-process} returns, and a missing or @code{nil}
+@var{process} means that the current buffer's process should be
+killed.) Calling @code{delete-process} on a running process
+terminates it, updates the process status, and runs the sentinel
+immediately. If the process has already terminated, calling
+@code{delete-process} has no effect on its status, or on the running
+of its sentinel (which will happen sooner or later).
If the process object represents a network, serial, or pipe
connection, its status changes to @code{closed}; otherwise, it changes
diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi
index c9828f9c868..21a2c6c51e4 100644
--- a/doc/lispref/searching.texi
+++ b/doc/lispref/searching.texi
@@ -549,12 +549,12 @@ can act. It is poor practice to depend on this behavior; quote the
special character anyway, regardless of where it appears.
As a @samp{\} is not special inside a character alternative, it can
-never remove the special meaning of @samp{-} or @samp{]}. So you
-should not quote these characters when they have no special meaning
-either. This would not clarify anything, since backslashes can
-legitimately precede these characters where they @emph{have} special
-meaning, as in @samp{[^\]} (@code{"[^\\]"} for Lisp string syntax),
-which matches any single character except a backslash.
+never remove the special meaning of @samp{-}, @samp{^} or @samp{]}.
+You should not quote these characters when they have no special
+meaning. This would not clarify anything, since backslashes
+can legitimately precede these characters where they @emph{have}
+special meaning, as in @samp{[^\]} (@code{"[^\\]"} for Lisp string
+syntax), which matches any single character except a backslash.
In practice, most @samp{]} that occur in regular expressions close a
character alternative and hence are special. However, occasionally a
@@ -823,21 +823,22 @@ the characters that stand for them.
matches any character whose syntax is not @var{code}.
@cindex category, regexp search for
-@item \c@var{c}
-matches any character whose category is @var{c}. Here @var{c} is a
-character that represents a category: thus, @samp{c} for Chinese
-characters or @samp{g} for Greek characters in the standard category
-table. You can see the list of all the currently defined categories
-with @kbd{M-x describe-categories @key{RET}}. You can also define
-your own categories in addition to the standard ones using the
-@code{define-category} function (@pxref{Categories}).
-
-@item \C@var{c}
-matches any character whose category is not @var{c}.
+@item \c@var{code}
+matches any character whose category is @var{code}. Here @var{code}
+is a character that represents a category: for example, in the standard
+category table, @samp{c} stands for Chinese characters and @samp{g}
+stands for Greek characters. You can see the list of all the
+currently defined categories with @w{@kbd{M-x describe-categories
+@key{RET}}}. You can also define your own categories in addition to
+the standard ones using the @code{define-category} function
+(@pxref{Categories}).
+
+@item \C@var{code}
+matches any character whose category is not @var{code}.
@end table
The following regular expression constructs match the empty string---that is,
-they don't use up any characters---but whether they match depends on the
+they don't consume any characters---but whether they match depends on the
context. For all, the beginning and end of the accessible portion of
the buffer are treated as if they were the actual beginning and end of
the buffer.
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 97908bea001..57763c146da 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -5508,7 +5508,7 @@ pixels, rather than in units of the normal line height.
@end example
@end defun
-@defun set-window-vscroll window lines &optional pixels-p
+@defun set-window-vscroll window lines &optional pixels-p preserve-vscroll-p
This function sets @var{window}'s vertical scroll position to
@var{lines}. If @var{window} is @code{nil}, the selected window is
used. The argument @var{lines} should be zero or positive; if not, it
@@ -5530,6 +5530,12 @@ The return value is the result of this rounding.
If @var{pixels-p} is non-@code{nil}, @var{lines} specifies a number of
pixels. In this case, the return value is @var{lines}.
+
+Normally, the vscroll does not take effect on windows that aren't the
+@code{minibuffer-scroll-window} or the selected window when the
+mini-window is resized (@pxref{Minibuffer Windows}). This ``frozen''
+behavior is disabled when the @var{preserve-vscroll-p} parameter is
+non-@code{nil}, which means to set the vscroll as usual.
@end defun
@defvar auto-window-vscroll
diff --git a/etc/HELLO b/etc/HELLO
index dbbcc0493bf..b64aacfbe5b 100644
--- a/etc/HELLO
+++ b/etc/HELLO
@@ -59,6 +59,8 @@ Hindi (हिंदी) नमसà¥à¤¤à¥‡ / नमसà¥à¤•à¤¾à¤° ।
Inuktitut (áƒá“„ᒃᑎá‘ᑦ) áŠáƒ
Italian (italiano) Ciao / Buon giorno
Javanese (ꦧꦱꦗꦮꦶ) console.log("ꦲꦭꦺꦴ");
+
+Kaithi (ð‘‚𑂶𑂟𑂲) 𑂩𑂰𑂧𑂩𑂰𑂧
Kannada (ಕನà³à²¨à²¡) ನಮಸà³à²•à²¾à²°
Khmer (ភាសាážáŸ’មែរ) ជំរាបសួរ
Lakota (Lakȟotiyapi) Taŋyáŋ yahí!
@@ -73,6 +75,7 @@ Norwegian (norsk) Hei / God dag
Oriya (ଓଡ଼ିଆ) ଶà­à¬£à¬¿à¬¬à­‡
Polish (język polski) Dzień dobry! / Cześć!
Russian (руÑÑкий) ЗдраÌвÑтвуйте!
+Sharada (𑆯𑆳𑆫𑆢𑆳) 𑆤𑆩𑆱𑇀𑆑𑆳𑆫
Sinhala (සිංහල) ආයුබà·à·€à¶±à·Š
Slovak (slovenÄina) Dobrý deň
Slovenian (slovenÅ¡Äina) Pozdravljeni!
@@ -84,6 +87,7 @@ TaiViet (êªêª«êª±êª£ ꪼꪕ) ꪅꪰꪙꫂ ꪨꪮꫂ êªêª«êª± / ꪅꪽ ꪨꪷ ê
Thai (ภาษาไทย) สวัสดีครับ / สวัสดีค่ะ
Tibetan (བོད་སà¾à½‘་) བཀྲ་ཤིས་བདེ་ལེགས༎
Tigrigna (ትáŒáˆ­áŠ›) ሰላማት
+Tirhuta (𑒞𑒱𑒩𑒯𑒳𑒞𑒰) 𑒣𑓂𑒩𑒢𑒰𑒧 / 𑒮𑒲𑒞𑒰𑒩𑒰𑒧
Turkish (Türkçe) Merhaba
Ukrainian (українÑька) Вітаю
Vietnamese (tiếng Việt) Chào bạn
diff --git a/etc/NEWS b/etc/NEWS
index 6637eda00c8..8404a3616e0 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -137,6 +137,13 @@ of 'user-emacs-directory'.
* Incompatible changes in Emacs 29.1
---
+** Isearch in *Help* and *info* now char-folds quote characters by default.
+This means that you can say 'C-s `foo' (GRAVE ACCENT) if the buffer
+contains "‘foo" (LEFT SINGLE QUOTATION MARK) and the like. These
+quotation characters look somewhat similar in some fonts. To switch
+this off, disable the new 'isearch-fold-quotes-mode' minor mode.
+
+---
** Sorting commands no longer necessarily change modification status.
In earlier Emacs versions, commands like 'M-x sort-lines' would always
change buffer modification status to "modified", whether they changed
@@ -238,9 +245,24 @@ encouraged to test timestamp-related code with this variable set to
nil, as it will default to nil in a future Emacs version and will be
removed some time after that.
++++
+** Functions which recreate the *scratch* buffer now also initialize it.
+When functions like 'other-buffer' and 'server-execute' recreate
+*scratch*, they now also insert 'initial-scratch-message' and set
+the major mode according to 'initial-major-mode', like at Emacs
+startup. Previously, these functions ignored
+'initial-scratch-message' and left *scratch* in 'fundamental-mode'.
+
* Changes in Emacs 29.1
+---
+** 'delete-process' is now a command.
+When called interactively, it will kill the process running in the
+current buffer (if any). This can be useful if you have runaway
+output in the current buffer (from a process or a network connection),
+and want to stop it.
+
+++
** New command 'restart-emacs'.
This is like 'save-buffers-kill-emacs', but instead of just killing
@@ -455,6 +477,15 @@ This allows you to enter emoji using short strings, eg :face_palm: or
** Help
+++
+*** New doc string syntax to indicate that symbols shouldn't be links.
+When displaying doc strings in *Help* buffers, strings that are
+"`like-this'" are made into links (if they point to a bound
+function/variable). This can lead to false positives when talking
+about values that are symbols that happen to have the same names as
+functions/variables. To inhibit this buttonification, the new
+"\\+`like-this'" syntax can be used.
+
++++
*** New user option 'help-window-keep-selected'.
If non-nil, commands to show the info manual and the source will reuse
the same window the *Help* buffer is shown in.
@@ -696,7 +727,7 @@ The options 'mouse-wheel-down-alternate-event',
and 'mouse-wheel-right-alternate-event' have been added to better
support systems where two kinds of wheel events can be received.
-** Editing complex text layout (CTL) scripts
+** Internationalization changes
*** The <Delete> function key now allows deleting the entire composed sequence.
For the details, see the item about the 'delete-forward-char' command
@@ -715,9 +746,40 @@ This language environment supports Brahmi, which is a historical
script that was used in ancient South Asia. A new input method,
'brahmi', is provided to type text in this script.
+*** New language environment "Kaithi".
+This language environment supports Kaithi or Kayasthi, which was
+an important writing system of the past mainly used for administrative
+purposes. A new input method, 'kaithi', is provided to type text in
+this script.
+
+*** New language environment "Tirhuta".
+This language environment supports Tirhuta or Mithilaakshar, which is
+used to write the Maithili language. A new input method, 'tirhuta',
+is provided to type text in this script.
+
+*** New language environment "Sharada".
+This language environment supports the Sharada script. Named after the
+goddess of learning, this script is used to write the Kashmiri language.
+A new input method, 'sharada', is provided to type text in this script.
+
+---
+*** New Greek translation of the Emacs tutorial.
+Type 'C-u C-h t' to select it in case your language setup does not do
+so automatically.
+
* Changes in Specialized Modes and Packages in Emacs 29.1
+** dabbrev
+
+---
+*** New function 'dabbrev-capf' for use on 'completion-at-point-functions'
+
++++
+*** New user option 'dabbrev-ignored-buffer-modes'.
+Buffers with major modes in this list will be ignored. By default,
+this includes "binary" buffers like 'archive-mode' and 'image-mode'.
+
** Package
+++
@@ -725,6 +787,11 @@ script that was used in ancient South Asia. A new input method,
This command allows you to upgrade packages without using 'M-x
list-packages'.
++++
+*** New DWIM action on 'x'.
+If no packages are marked, 'x' will install the package under point if
+it isn't already, and remove it if it is installed.
+
** Miscellaneous
+++
@@ -838,7 +905,7 @@ When this user option names a face, the current
candidate in the "*Completions*" buffer is highlighted with that face.
The nil value disables this highlighting.
----
++++
*** Choosing a completion with a prefix argument doesn't exit the minibuffer.
This means that typing 'C-u RET' on a completion candidate in the
"*Completions*" buffer inserts the completion to the minibuffer,
@@ -1094,6 +1161,11 @@ filters and displayed with the specified color.
** term-mode
---
+*** New user option 'term-bind-function-keys'.
+If non-nil, 'term-mode' will pass the function keys on to the
+underlying shell instead of using the normal Emacs bindings.
+
+---
*** Support for ANSI 256-color and 24-bit colors, italic and other fonts.
Term-mode can now display 256-color and 24-bit color codes. It can
also handle ANSI codes for faint, italic and blinking text, displaying
@@ -1500,6 +1572,22 @@ Emacs buffers, like indentation and the like. The new ert function
* Incompatible Lisp Changes in Emacs 29.1
++++
+** 'buffer-modified-p' has been extended.
+This function was previously documented to return only nil or t. This
+has been changed to nil/'autosaved'/non-nil. The new 'autosaved'
+value means that the buffer is modified, but that it hasn't been
+modified after the last auto-save.
+
+---
+** 'with-silent-modifications' also restores buffer autosave status.
+'with-silent-modifications' is a macro meant to be used by the font
+locking machinery to allow applying text properties without changing
+the modification status of the buffer. However, it didn't restore the
+buffer autosave status, so applying font locking to a modified buffer
+that had already been auto-saved would trigger another auto-saving.
+This is no longer the case.
+
---
** 'prin1' doesn't always escape "." and "?" in symbols any more.
Previously, symbols like 'foo.bar' would be printed by 'prin1' as
@@ -1636,6 +1724,23 @@ functions.
* Lisp Changes in Emacs 29.1
++++
+*** 'restore-buffer-modified-p' can now alter buffer auto-save state.
+With a FLAG value of 'autosaved', it will mark the buffer as having
+been auto-saved after the last modification.
+
+---
+*** New minor mode 'isearch-fold-quotes-mode'.
+This sets up 'search-default-mode' so that quote characters are
+char-folded into each other. It is used, by default, in *Help* and
+*info* buffers.
+
++++
+** New macro 'buffer-local-set-state'.
+This is a helper macro to be used by minor modes that wish to restore
+buffer-local variables back to their original states when the mode is
+switched off.
+
---
** New macro 'with-buffer-unmodified-if-unchanged'.
If the buffer is marked as unmodified, and code does modifications
@@ -2020,6 +2125,11 @@ dimensions.
Specifying a cons as the FROM argument allows to start measuring text
from a specified amount of pixels above or below a position.
++++
+** 'set-window-vscroll' now accepts a new argument PRESERVE-VSCROLL-P.
+This means the vscroll will not be reset when set on a window that is
+"frozen" due to a mini-window being resized.
+
** XDG support
---
@@ -2050,6 +2160,12 @@ This holds the value of the previous call to 'set-locale-environment'.
This macro can be used to change the locale temporarily while
executing code.
+** table.el
+
+---
+*** New user option 'table-latex-environment'.
+This allows switching between "table" and "tabular".
+
** Tabulated List Mode
+++
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 270de600d66..3e0b73a4d59 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -1874,6 +1874,33 @@ this, you can remove the X resource or put this in your init file:
(xterm-remove-modify-other-keys)
+** The shift TAB key combination works as meta TAB on a Linux console.
+
+This happens because on your keyboard layout, S-TAB produces the same
+keycodes as typing ESC TAB individually. The best way to solve this
+is to modify your keyboard layout to produce different codes, and tell
+Emacs what these new codes mean.
+
+The current keyboard layout will probably be a .map.gz file somewhere
+under /usr/share/keymaps. Identify this file, possibly from a system
+initialization file such as /etc/conf.d/keymaps. Run gunzip on it to
+decompress it, and amend the entries for keycode 15 to look something
+like this:
+
+keycode 15 = Tab
+ alt keycode 15 = Meta_Tab
+ shift keycode 15 = F219
+string F219 = "\033[4}\011" # Shift+<tab>
+
+After possibly saving this file under a different name, compress it
+again using gzip. Amend /etc/conf.d/keyamps, etc., if needed.
+Further details can be found in the man page for loadkeys.
+
+Then add the following line near the start of your site-start.el or
+.emacs or init.el file:
+
+(define-key input-decode-map "\e[4}\t" 'backtab)
+
** Emacs spontaneously displays "I-search: " at the bottom of the screen.
This means that Control-S/Control-Q (XON/XOFF) "flow control" is being
diff --git a/etc/tutorials/TUTORIAL.el_GR b/etc/tutorials/TUTORIAL.el_GR
new file mode 100644
index 00000000000..b34fa5403c7
--- /dev/null
+++ b/etc/tutorials/TUTORIAL.el_GR
@@ -0,0 +1,1267 @@
+Εκμάθηση του Emacs. Δες το τέλος για ÏŒÏους αντιγÏαφής.
+
+Στο Emacs οι εντολές γενικά πεÏιλαμβάνουν το πλήκτÏο CONTROL (συχνά
+αναγÏάφεται ως Ctrl) ή το πλήκτÏο META (συνήθως επισημαίνεται ως ALT).
+Αντί να γÏάφουμε το πλήÏες όνομα κάθε φοÏά, θα χÏησιμοποιοÏμε τις εξής
+συντομογÏαφίες:
+
+ C-<χαÏ> σημαίνει κÏάτα πατημένο το πλήκτÏο CONTROL καθώς
+ πληκτÏολογείς τον χαÏακτήÏα <χάÏ>. Συνεπώς, C-f είναι:
+ κÏάτα πατημένο το CONTROL και πληκτÏολόγησε το f.
+ M-<χαÏ> σημαίνει κÏάτα πατημένο το πλήκτÏο META ή ALT καθώς
+ πληκτÏολογείς τον χαÏακτήÏα <χάÏ>. Σε πεÏίπτωση που δεν
+ υπάÏχει πλήκτÏο META ή ALT, πληκτÏολόγησε και απελευθέÏωσε
+ το πλήκτÏο ESC και κατόπιν πληκτÏολόγησε τον <χάÏ>.
+ ΓÏάφουμε <ESC> για το πλήκτÏο ESC.
+
+Σημαντική σημείωση: για να τεÏματίσεις το Emacs, πληκτÏολόγησε C-x
+C-c. (ΔÏο χαÏακτήÏες.) Για να ακυÏώσεις μια μεÏικώς πληκτÏολογημένη
+εντολή, πληκτÏολόγησε C-g.
+Για να σταματήσεις την εκμάθηση, πληκτÏολόγησε C-x k, κατόπιν <Return>
+στην Ï€ÏοτÏοπή.
+Οι χαÏακτήÏες ">>" στο αÏιστεÏÏŒ πεÏιθώÏιο δείχνουν οδηγίες για να
+δοκιμάσεις μια εντολή. Για παÏάδειγμα:
+<<Blank lines inserted around following line by help-with-tutorial>>
+[Κενό για διδακτικοÏÏ‚ σκοποÏÏ‚. Το κείμενο συνεχίζεται παÏακάτω.]
+
+>> ΤώÏα πληκτÏολόγησε C-v (δες επόμενη οθόνη) ώστε να κυλήσεις πιο
+ κάτω στην παÏοÏσα εκμάθηση. (Κάνε το, κÏατώντας πατημένο το
+ πλήκτÏο CONTROL και πληκτÏολογώντας v.) Από εδώ και στο εξής,
+ παÏακαλώ κάνε αυτό όποτε φτάνεις στο τέλος της οθόνης.
+
+Σημείωσε πως υπάÏχει επικάλυψη δÏο γÏαμμών όταν κυλάς μια πλήÏη οθόνη:
+αυτή σου Ï€ÏοσφέÏει κάποια συνέχεια ώστε να συνεχίσεις να διαβάζεις το
+κείμενο.
+
+Αυτό είναι αντίγÏαφο του κειμένου εκμάθησης του Emacs, ελαφÏά
+Ï„Ïοποποιημένο για εσένα. ΠαÏακάτω θα σου αναθέσουμε να δοκιμάσεις
+μεÏικές εντολές που Ï„ÏοποποιοÏν το εν λόγω κείμενο. Μην ανησυχείς αν
+Ï„Ïοποποιήσεις αυτό το κείμενο Ï€Ïιν σου το ζητήσουμε· η Ï€Ïάξη αυτή
+αναφέÏεται ως «επεξεÏγασία» και το Emacs χÏησιμοποιείται για αυτόν τον
+σκοπό.
+
+Το Ï€Ïώτο Ï€Ïάγμα που Ï€Ïέπει να γνωÏίζεις είναι πως να κινείσαι από το
+ένα σημείο σε άλλο σημείο του κειμένου. Ήδη ξέÏεις πως να πηγαίνεις
+μια οθόνη Ï€Ïος τα κάτω με το C-v. Για να κινηθείς αντίστÏοφα,
+πληκτÏολόγησε M-v (κÏάτα πατημένο το META και πληκτÏολόγησε το v, ή
+πληκτÏολόγησε <ESC>v εάν δεν έχει πλήκτÏο META ή ALT).
+
+>> Δοκίμασε να πληκτÏολογήσεις M-v και μετά C-v μεÏικές φοÏές.
+
+Είναι αποδεκτό να κυλήσεις το κείμενο με άλλους Ï„Ïόπους, αν τους
+ξέÏεις.
+
+* ΣΥÎΟΨΗ
+--------
+
+Οι εξής εντολές είναι χÏήσιμες για να βλέπεις πλήÏης οθόνες:
+
+ C-v Κινήσου μπÏοστά/κάτω μια πλήÏη οθόνη
+ M-v Κινήσου πίσω/πάνω μια πλήÏη οθόνη
+
+ C-l ΚαθάÏισε την οθόνη επανεμφανίζοντας το κείμενο της και
+ μεταφέÏοντας τον δείκτη (κέÏσοÏα) στο κέντÏο της.
+ (Αυτό είναι CONTROL-L, όχι CONTROL-1.)
+
+>> Εντόπισε τον δείκτη και σημείωσε το κείμενο πέÏιξ του. Μετά
+ πληκτÏολόγησε C-l. ΞαναβÏές τον δείκτη και παÏατήÏησε το κείμενο
+ δίπλα του, αλλά Ï„ÏŽÏα Ï€Ïόσεξε πως βÏίσκεται στο κέντÏο της οθόνης.
+ Εάν πατήσεις C-l πάλι, το κείμενο αυτό θα μετατοπιστεί στο πάνω
+ μέÏος της οθόνης. Πάτα το C-l ξανά και θα πάει στο κάτω μέÏος.
+
+ΜποÏείς επίσης να χÏησιμοποιήσεις τα πλήκτÏα PageUp και PageDn για να
+κινηθείς ανά πλήÏη οθόνη, εάν ο ακÏοδέκτης (τεÏματικό) σου τα έχει,
+ωστόσο είναι πιο αποτελεσματικό να χÏησιμοποιείς τα C-v και M-v.
+
+
+* ΒΑΣΙΚΟΣ ΕΛΕΓΧΟΣ ΤΟΥ ΔΕΙΚΤΗ
+----------------------------
+
+Η κίνηση ανά πλήÏη οθόνη είναι χÏήσιμη, αλλά πως θα πας σε
+συγκεκÏιμένο σημείο εντός του κειμένου της οθόνης;
+
+ΥπάÏχουν πολλοί Ï„Ïόποι να το επιτÏχεις αυτό. ΜποÏείς να
+χÏησιμοποιήσεις τα πλήκτÏα με τα βέλη, αλλά είναι πιο αποτελεσματικό
+να κÏατήσεις τα χέÏια σου στην κανονική θέση και να χÏησιμοποιήσεις
+τις εντολές C-p, C-b, C-f, και C-n. Οι χαÏακτήÏες αυτοί είναι το
+αντίστοιχο των τεσσάÏων πλήκτÏων με τα βέλη, κατά αυτόν τον Ï„Ïόπο:
+
+ ΠÏοηγοÏμενη γÏαμμή, C-p
+ :
+ :
+ Πίσω, C-b .... ΠαÏοÏσα θέση του δείκτη .... ΕμπÏός, C-f
+ :
+ :
+ Επόμενη γÏαμμή, C-n
+
+>> Μετακίνησε τον δείκτη στη μέση του διαγÏάμματος αυτοÏ
+ χÏησιμοποιώντας C-n ή C-p. Μετά πληκτÏολόγησε C-l για να δεις το
+ όλο διάγÏαμμα στο κέντÏο της οθόνης.
+
+Θα σου είναι ευκολότεÏο να θυμάσαι αυτά τα γÏάμματα από τις λέξεις τις
+οποίες αναφέÏουν στην Αγγλική: P για Ï€ÏοηγοÏμενο (previous), N για
+επόμενο (next), B για πίσω (backward), και F για εμπÏός (forward). Θα
+χÏησιμοποιείς διαÏκώς αυτές τις βασικές εντολές για την τοποθέτηση του
+δείκτη.
+
+>> Κάνε μεÏικά C-n μέχÏι να φέÏεις τον δείκτη σε αυτή την γÏαμμή.
+
+>> Κινήσου εντός της γÏαμμής με μεÏικά C-f και μετά πάνω με κάποια
+ C-p. Δες τι κάνει το C-p όταν βÏίσκεται στην μέση της γÏαμμής.
+
+Κάθε γÏαμμή κειμένου τελειώνει με τον χαÏακτήÏα νέας γÏαμμής, που
+επιτελεί τον σκοπό του διαχωÏÎ¹ÏƒÎ¼Î¿Ï Ï„Î·Ï‚ μίας γÏαμμής από την άλλη.
+(Συνήθως η τελευταία γÏαμμή σε ένα αÏχείο τελειώνει με τον χαÏακτήÏα
+νέας γÏαμμής, ωστόσο το Emacs δεν απαιτεί κάτι τέτοιο.)
+
+>> Δοκίμασε το C-b στην αÏχή της γÏαμμής. Θα μετακινήσει τον δείκτη
+ στο τέλος της Ï€ÏοηγοÏμενης γÏαμμής. Διότι κινείται Ï€Ïος τα πίσω
+ Ï€ÏοσπεÏνώντας τον χαÏακτήÏα νέας γÏαμμής.
+
+Το C-f έχει την ίδια συμπεÏιφοÏά με το C-b.
+
+>> Κάνε μεÏικά ακόμα C-b, ώστε να εντοπίσεις τον δείκτη. Κατόπιν
+ κάνε C-f για να γυÏίσεις στο τέλος της γÏαμμής. Μετά ένα ακόμα C-f
+ για να κινηθείς στην αÏχή της επόμενης γÏαμμής.
+
+Όταν κινείσαι πέÏα από το πάνω ή κάτω μέÏος της οθόνης, το κείμενο
+πέÏαν της άκÏης μετατοπίζεται εντός της οθόνης. Αυτό ονομάζεται
+«κÏλιση». ΕπιτÏέπει στο Emacs να φέÏει τον δείκτη στο οÏισμένο
+σημείο του κειμένου χωÏίς να κινηθεί εκτός της οθόνης.
+
+>> Δοκίμασε να κινήσεις τον δείκτη πέÏα από το κάτω μέÏος της οθόνης
+ με το C-n και δες τι συμβαίνει.
+
+Εάν η κίνηση ανά χαÏακτήÏα είναι Ï€Î¿Î»Ï Î±Ïγή, μποÏείς να κινηθείς ανά
+λέξη. Το M-f (META-f) πάει μπÏοστά μια λέξη και M-b πίσω μια λέξη.
+
+>> ΠληκτÏολόγησε μεÏικά M-f και M-b.
+
+Όταν βÏίσκεσαι στο μέσο μιας λέξης, το M-f πηγαίνει στο τέλος της.
+Όταν βÏίσκεσαι σε κενό Î¼ÎµÏ„Î±Î¾Ï Î»Î­Î¾ÎµÏ‰Î½, το M-f κινείται στο τέλος της
+ακόλουθης λέξης. Το M-b λειτουÏγεί αναλόγως Ï€Ïος την αντίθετη
+κατεÏθυνση.
+
+>> ΠληκτÏολόγησε M-f και M-b μεÏικές φοÏές, με C-f και C-b Î¼ÎµÏ„Î±Î¾Ï Ï„Î¿Ï…Ï‚
+ ώστε να παÏατηÏήσεις την δÏάση των M-f και M-b σε διάφοÏα σημεία
+ εντός και Î¼ÎµÏ„Î±Î¾Ï Î»Î­Î¾ÎµÏ‰Î½.
+
+ΠαÏατήÏησε την παÏάλληλο Î¼ÎµÏ„Î±Î¾Ï C-f και C-b από την μία, και M-f και
+M-b από την άλλη. Î Î¿Î»Ï ÏƒÏ…Ï‡Î½Î¬ οι Meta χαÏακτήÏες χÏησιμοποιοÏνται για
+Ï€Ïάξεις που σχετίζονται με μονάδες που οÏίζει η εκάστοτε γλώσσα
+(λέξεις, Ï€Ïοτάσεις, παÏαγÏάφους), ενώ οι Control χαÏακτήÏες επιδÏοÏν
+σε βασικά στοιχεία που είναι ανεξάÏτητα του τι επεξεÏγάζεσαι
+(χαÏακτήÏες, γÏαμμές, κτλ.).
+
+Αυτή η παÏάλληλος ισχÏει Î¼ÎµÏ„Î±Î¾Ï Î³Ïαμμών και Ï€Ïοτάσεων. C-a και C-e
+πηγαίνουν στην αÏχή και το τέλος της γÏαμμής, ενώ M-a και M-e
+πηγαίνουν στην αÏχή και το τέλος της Ï€Ïότασης.
+
+>> Δοκίμασε δÏο C-a και ÏστεÏα δÏο C-e.
+ Δοκίμασε δÏο M-a και ÏστεÏα δÏο M-e.
+
+ΠαÏατήÏησε πως αλλεπάλληλα C-a δεν κάνουν τίποτα, ενώ επανειλημμένα
+M-a συνεχίζουν να κινοÏνται ανά μία Ï€Ïόταση. ΠαÏότι δεν είναι
+ανάλογα, το καθένα φαντάζει φυσικό.
+
+Η θέση του δείκτη εντός του κειμένου ονομάζεται «σημείο» (point). Με
+άλλα λόγια, ο δείκτης δείχνει που βÏίσκεται το σημείο εντός του
+κειμένου στην οθόνη.
+
+Î™Î´Î¿Ï Î¼Î¯Î± σÏνοψη των απλών κινήσεων του δείκτη, συμπεÏιλαμβανομένων
+των εντολών για κίνηση ανά λέξη και Ï€Ïόταση:
+
+ C-f Κινήσου εμπÏός ένα χαÏακτήÏα
+ C-b Κινήσου πίσω ένα χαÏακτήÏα
+
+ M-f Κινήσου εμπÏός μία λέξη
+ M-b Κινήσου πίσω μία λέξη
+
+ C-n Κινήσου στην επόμενη γÏαμμή
+ C-p Κινήσου στην Ï€ÏοηγοÏμενη γÏαμμή
+
+ C-a Κινήσου στην αÏχή της γÏαμμής
+ C-e Κινήσου στο τέλος της γÏαμμής
+
+ M-a Κινήσου πίσω στην αÏχή της Ï€Ïότασης
+ M-e Κινήσου εμπÏός στο τέλος της Ï€Ïότασης
+
+>> Δοκίμασε όλες αυτές τις εντολές μεÏικές φοÏές για εξάσκηση. Αυτές
+ είναι οι πιο συνηθισμένες εντολές.
+
+ΔÏο άλλες σημαντικές κινήσεις του δείκτη είναι το M-< (META
+ΜικÏότεÏο), που κινείται στην αÏχή ολόκληÏου του κειμένου, και M->
+(META ΜεγαλÏτεÏο) που κινείται στο τέλος ολόκληÏου του κειμένου.
+
+Στους πλείστους ακÏοδέκτες (τεÏματικά), το '<' είναι στο ίδιο πλήκτÏο
+με το κόμμα, οπότε Ï€Ïέπει να κÏατάς πατημένο το shift για να το
+πληκτÏολογήσεις. Σε αυτοÏÏ‚ τους ακÏοδέκτες Ï€Ïέπει να χÏησιμοποιήσεις
+το shift και για το M-<, αλλιώς θα πατάς M-κόμμα.
+
+>> Δοκίμασε το M-< Ï„ÏŽÏα για να κινηθείς στην αÏχή αυτής της εκμάθησης.
+ Κατόπιν χÏησιμοποίησε το C-v επανειλημμένα για να επιστÏέψεις εδώ.
+
+>> ΤώÏα δοκίμασε το M-> για να κινηθείς στο τέλος αυτής της εκμάθησης.
+ Κατόπιν χÏησιμοποίησε το M-v επανειλημμένα για να επιστÏέψεις εδώ.
+
+ΜποÏείς επίσης να χÏησιμοποιήσεις τα πλήκτÏα με τα βέλη, εάν ο
+ακÏοδέκτης σου τα υποστηÏίζει. ΠÏοτείνουμε να μάθεις τα C-b, C-f, C-n
+και C-p για Ï„Ïεις λόγους. ΠÏώτον, δουλεÏουν σε όλων των ειδών τους
+ακÏοδέκτες. ΔεÏτεÏον, όταν αποκτήσεις εμπειÏία στην χÏήση του Emacs,
+θα διαπιστώσεις πως αυτοί οι χαÏακτήÏες του Control είναι πιο γÏήγοÏοι
+στην χÏήση παÏά τα βέλη (διότι δεν απομακÏÏνεις τα χέÏια σου από την
+θέση πληκτÏολόγησης δια αφής). ΤÏίτον, εφόσον διαμοÏφώσεις την
+συνήθεια να χÏησιμοποιείς τις εντολές με τους Control χαÏακτήÏες,
+μποÏείς πιο εÏκολα να μάθεις πιο Ï€Ïοηγμένες εντολές κίνησης.
+
+Οι πλείστες εντολές του Emacs δέχονται αÏιθμητική παÏάμετÏο: για τις
+πεÏισσότεÏες εντολές αυτή λειτουÏγεί ως μετÏητής επανάληψης. Ο Ï„Ïόπος
+που δίνεις σε μια εντολή αÏιθμητική παÏάμετÏο γίνεται πληκτÏολογώντας
+το C-u και μετά τα ψηφία Ï€ÏÎ¿Ï„Î¿Ï Ï€Î»Î·ÎºÏ„Ïολογήσεις την εντολή. Εάν έχεις
+το πλήκτÏο META (ή ALT), υπάÏχει άλλος εναλλακτικός Ï„Ïόπος εισαγωγής
+αÏιθμητικής παÏαμέτÏου: πληκτÏολόγησε τα ψηφία κÏατώντας πατημένο το
+πλήκτÏο META. ΣυνιστοÏμε να μάθεις την μέθοδο του C-u γιατί ισχÏει σε
+όλους τους ακÏοδέκτες. Η αÏιθμητική παÏάμετÏος ονομάζεται επίσης
+«πÏοθεματική παÏάμετÏος», καθώς πληκτÏολογείς την παÏάμετÏο Ï€Ïιν την
+εντολή στην οποία δίνεται.
+
+Για παÏάδειγμα, C-u 8 C-f κινείται εμπÏός οκτώ χαÏακτήÏες.
+
+>> Δοκίμασε να χÏησιμοποιήσεις το C-n ή C-p με αÏιθμητική παÏάμετÏο
+ για να κινήσεις τον δείκτη σε μια γÏαμμή κοντά σε αυτή με μόνο μία
+ εντολή.
+
+Οι πλείστες εντολές χÏησιμοποιοÏν την αÏιθμητική παÏάμετÏο ως μετÏητή
+επανάληψης, αλλά μεÏικές εντολές την χÏησιμοποιοÏν με διαφοÏετικό
+Ï„Ïόπο. ΑÏκετές εντολές (αλλά καμία από αυτές που έμαθες έως Ï„ÏŽÏα) την
+χÏησιμοποιοÏν ως ένδειξη--η παÏουσία Ï€Ïοθεματικής παÏαμέτÏου,
+ανεξαÏτήτως της αξίας της, κάνει την εντολή να εκτελέσει κάτι
+διαφοÏετικό.
+
+Τα C-v και M-v συνιστοÏν άλλο ένα είδος εξαίÏεσης. Όταν τους δοθεί
+παÏάμετÏος, κυλοÏν το κείμενο πάνω ή κάτω κατά τόσες γÏαμμές, αντί για
+πλήÏη οθόνη. Για παÏάδειγμα, C-u 8 C-v κυλάει πάνω κατά 8 γÏαμμές.
+
+>> Δοκίμασε να πληκτÏολογήσεις C-u 8 C-v Ï„ÏŽÏα.
+
+Αυτό Ï€Ïέπει να κÏλησε το κείμενο πάνω κατά 8 γÏαμμές. Αν θέλεις να το
+φέÏεις κάτω πάλι δοκίμασε την ίδια αÏιθμητική παÏάμετÏο με το M-v.
+
+Εάν χÏησιμοποιείς γÏαφική Ï€Ïοβολή, όπως το X ή MS-Windows, θα Ï€Ïέπει
+να υπάÏχει μια ψηλή, οÏθογώνια επιφάνεια σε πλευÏά του παÏαθÏÏου του
+Emacs που είναι γνωστή και ως η μπάÏα κÏλισης (scroll bar). ΜποÏείς
+να κυλήσεις το κείμενο πατώντας με το ποντίκι πάνω στην μπάÏα κÏλισης.
+
+Αν το ποντίκι σου έχει Ïοδέλα, μποÏείς να την χÏησιμοποιήσεις για
+κÏλιση.
+
+
+* ΑΠΤΟ EMACS ΠΑΨΕΙ ÎΑ ΑÎΤΑΠΟΚΡΙÎΕΤΑΙ
+-------------------------------------
+
+Αν το Emacs πάψει να ανταποκÏίνεται στις εντολές σου, μποÏείς να το
+σταματήσεις με ασφάλεια πληκτÏολογώντας C-g. ΜποÏείς να
+χÏησιμοποιήσεις το C-g για να σταματήσεις μια εντολή που παίÏνει πολÏ
+χÏόνο να εκτελεστεί.
+
+ΜποÏείς επίσης να χÏησιμοποιήσεις το C-g για να καταÏγήσεις μια
+αÏιθμητική παÏάμετÏο ή την αÏχή μιας εντολής που δεν θέλεις να
+ολοκληÏώσεις.
+
+>> ΠληκτÏολόγησε C-u 100 για να φτιάξεις μια αÏιθμητική παÏάμετÏο του
+ 100, μετά πληκτÏολόγησε C-g. ΤώÏα πληκτÏολόγησε C-f. Θα Ï€Ïέπει να
+ κινηθεί μόνο ένα χαÏακτήÏα, διότι ακÏÏωσες την παÏάμετÏο με το C-g.
+
+Σε πεÏίπτωση που έχεις πληκτÏολογήσει το <ESC> κατά λάθος, μποÏείς να
+το ξεφοÏτωθείς με το C-g.
+
+
+* ΑΠΕÎΕΡΓΟΠΟΙΗΜΕÎΕΣ ΕÎΤΟΛΕΣ
+---------------------------
+
+Κάποιες εντολές του Emacs είναι «απενεÏγοποιημένες» ώστε νέοι χÏήστες
+να μην τις χÏησιμοποιήσουν κατά λάθος.
+
+Αν πληκτÏολογήσεις μία από αυτές τις απενεÏγοποιημένες εντολές, το
+Emacs παÏουσιάζει μήνυμα που αναφέÏει ποια είναι η εντολή και σου ζητά
+αν θέλεις να την εκτελέσεις.
+
+Εάν Ï€Ïάγματι θες να δοκιμάσεις την εντολή, πληκτÏολόγησε <SPC> (το
+κενό) ως απάντηση στην εÏώτηση. Κανονικά, αν δεν θέλεις να εκτελέσεις
+την απενεÏγοποιημένη εντολή απαντάς με το «n».
+
+>> ΠληκτÏολόγησε C-x C-l (που είναι απενεÏγοποιημένη εντολή) και μετά
+ πληκτÏολόγησε n ως απάντηση.
+
+
+* ΠΑΡΑΘΥΡΑ
+----------
+
+Το Emacs μποÏεί να έχει πολλά «παÏάθυÏα», με το καθένα να δείχνει το
+δικό του κείμενο. Θα εξηγήσουμε παÏακάτω πως να χÏησιμοποιείς πολλά
+παÏάθυÏα. Για την ÏŽÏα θέλουμε να εξηγήσουμε πως θα ξεφοÏτωθείς
+πλεονάζοντα παÏάθυÏα για να επιστÏέψεις στην βασική επεξεÏγασία εντός
+ενός παÏαθÏÏου. Είναι απλό:
+
+ C-x 1 Ένα παÏάθυÏο (δηλαδή εξαφάνισε όλα τα άλλα παÏάθυÏα)
+
+Αυτό Ï€Ïόκειται για το CONTROL-x που ακολουθείται από το ψηφίο 1. Το
+C-x 1 μεγιστοποιεί το παÏάθυÏο που πεÏιέχει τον δείκτη. ΔιαγÏάφει τα
+άλλα παÏάθυÏα.
+
+>> ΦέÏε τον δείκτη σε αυτή την γÏαμμή και πληκτÏολόγησε C-u 0 C-l.
+>> ΠληκτÏολόγησε C-h k C-f.
+ Δες πως το παÏάθυÏο συÏÏικνώνεται, καθώς ένα νέο εμφανίζεται για να
+ παÏουσιάσει την καταγÏαφή της εντολής C-f.
+
+>> ΠληκτÏολόγησε C-x 1 και δες πως το παÏάθυÏο της καταγÏαφής
+ εξαφανίζεται.
+
+ΥπάÏχει σειÏά εντολών που ξεκινοÏν με το CONTROL-x· πολλές εξ αυτών
+έχουν να κάνουν με παÏάθυÏα (windows), αÏχεία (files), αποσβεστήÏες
+(buffers), και τα σχετικά. Αυτές οι εντολές είναι δÏο, Ï„Ïία ή τέσσεÏα
+γÏάμματα μάκÏος.
+
+
+* ΕΙΣΑΓΟÎΤΑΣ ΚΑΙ ΔΙΑΓΡΑΦΟÎΤΑΣ
+-----------------------------
+
+Αν θέλεις να εισάγεις κείμενο, απλά πληκτÏολόγησε το. Κοινοί
+χαÏακτήÏες, όπως το Α, 7, *, κτλ. εισάγονται καθώς τους πληκτÏολογείς.
+Για να εισάγεις τον χαÏακτήÏα νέας γÏαμμής, πληκτÏολόγησε <Return>
+(αυτό είναι το πλήκτÏο που μεÏικές φοÏές αναγÏάφεται ως «Enter»).
+
+Για να διαγÏάψεις τον χαÏακτήÏα ακÏιβώς Ï€Ïιν από το τωÏινό σημείο του
+δείκτη, πληκτÏολόγησε <DEL>. Αυτό είναι το πλήκτÏο που συνήθως
+αναγÏάφεται στο πληκτÏολόγιο ως «Backspace»--το ίδιο θα
+χÏησιμοποιοÏσες κανονικά κι εκτός Emacs για να διαγÏάψεις τον
+τελευταίο χαÏακτήÏα που εισήγαγες.
+
+Συνήθως υπάÏχει άλλο ένα πλήκτÏο που αναγÏάφεται ως <Delete>, αλλά
+αυτό είναι διαφοÏετικό από αυτό που Ï€ÏοαναφέÏαμε και που εννοοÏμε με
+το <DEL> του Emacs.
+
+>> Κάνε αυτό Ï„ÏŽÏα--πληκτÏολόγησε μεÏικοÏÏ‚ χαÏακτήÏες, μετά διάγÏαψε
+ τους πατώντας το <DEL> μεÏικές φοÏές. Μην ανησυχείς για την
+ Ï„Ïοποποίηση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… αÏχείου: δεν Ï„Ïοποποιείς το κÏÏιο κείμενο
+ εκμάθησης. Αυτό είναι το Ï€Ïοσωπικό σου αντίγÏαφο.
+
+Όταν η γÏαμμή του κειμένου γίνεται Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î· για μια γÏαμμή της
+οθόνης, η γÏαμμή του κειμένου «συνεχίζεται» σε δεÏτεÏη γÏαμμή οθόνης.
+Εάν χÏησιμοποιείς γÏαφική Ï€Ïοβολή, καμπυλωτά βελάκια θα εμφανιστοÏν
+στα στενά πλαίσια που βÏίσκονται στα άκÏα της επιφάνειας του κειμένου
+(οι «παÏυφές» αÏιστεÏά και δεξιά), για να επισημάνουν που συνεχίζεται
+η γÏαμμή. Εάν χÏησιμοποιείται Ï€Ïοβολή κειμένου, η συνεχιζόμενη γÏαμμή
+παÏουσιάζεται με την αντίστÏοφη κάθετο ('\') στην δεξιότεÏη στήλη της
+οθόνης.
+
+>> Εισήγαγε κείμενο μέχÏις ότου φτάσεις στο δεξί πεÏιθώÏιο και
+ συνέχισε να Ï€Ïοσθέτεις. Θα δεις να εμφανίζεται η γÏαμμή συνέχειας.
+
+>> Πάτα <DEL> επανειλημμένα για να διαγÏάψεις το κείμενο μέχÏι που η
+ γÏαμμή να χωÏάει ξανά στην οθόνη. Η γÏαμμή συνέχειας θα χαθεί.
+
+ΜποÏείς να διαγÏάψεις τον χαÏακτήÏα νέας γÏαμμής όπως κάθε άλλο
+χαÏακτήÏα. ΔιαγÏάφοντας τον χαÏακτήÏα νέας γÏαμμής Î¼ÎµÏ„Î±Î¾Ï Î´Ïο γÏαμμών
+έχει σαν αποτέλεσμα την συνένωση τους σε μία γÏαμμή. Εάν σαν
+αποτέλεσμα η γÏαμμή είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î·, θα παÏουσιαστεί με την γÏαμμή
+συνέχειας.
+
+>> Μετακίνησε τον δείκτη στην αÏχή της γÏαμμής και πληκτÏολόγησε
+ <DEL>. Αυτό θα συνενώσει την γÏαμμή με την από πάνω της.
+
+>> ΠληκτÏολόγησε <Return> για να επανεισάγεις τον χαÏακτήÏα νέας
+ γÏαμμής που μόλις διέγÏαψες.
+
+Το πλήκτÏο <Return> είναι ειδικό, καθώς πληκτÏολογώντας το μποÏεί να
+κάνει πεÏισσότεÏα Ï€Ïάγματα πέÏαν της εισαγωγής του χαÏακτήÏα νέας
+γÏαμμής. Ανάλογα με το πεÏιβάλλων κείμενο, μποÏεί να Ï€Ïοσθέσει κενό
+μετά τον χαÏακτήÏα νέας γÏαμμής, ώστε όταν αÏχίσεις να γÏάφεις στην
+νέα γÏαμμή, το κείμενο να στοιχίζεται με την Ï€ÏοηγοÏμενη γÏαμμή.
+Ονομάζουμε αυτή την συμπεÏιφοÏά (όπου το πάτημα ενός πλήκτÏου κάνει
+κάτι παÏαπάνω από την εισαγωγή του ÏƒÏ‡ÎµÏ„Î¹ÎºÎ¿Ï Ï‡Î±ÏακτήÏα) «ηλεκτÏική».
+
+>> Î™Î´Î¿Ï Î­Î½Î± παÏάδειγμα της ηλεκτÏικότητας του <Return>.
+ ΠληκτÏολόγησε <Return> στο τέλος αυτής της γÏαμμής.
+
+Κανονικά θα δεις πως μετά την εισαγωγή του χαÏακτήÏα νέας γÏαμμής, το
+Emacs εισάγει κενά ώστε ο δείκτης να βÏίσκεται ακÏιβώς κάτω από το
+«Π» του «ΠληκτÏολόγησε».
+
+Θυμήσου πως οι πλείστες εντολές του Emacs δέχονται μετÏητή επανάληψης·
+αυτό πεÏιλαμβάνει την εισαγωγή κειμένου. Επαναλαμβάνοντας ένα
+χαÏακτήÏα κειμένου τον εισάγει πολλές φοÏές.
+
+>> Δοκίμασε το Ï„ÏŽÏα -- πληκτÏολόγησε C-u 8 * για να εισάγεις ********.
+
+Έχεις ήδη μάθει τους πιο βασικοÏÏ‚ Ï„Ïόπους για την πληκτÏολόγηση
+κειμένου στο Emacs και την διόÏθωση των λαθών. ΜποÏείς επίσης να
+διαγÏάψεις λέξεις και γÏαμμές. Î™Î´Î¿Ï Î· σÏνοψη των Ï€Ïάξεων διαγÏαφής:
+
+ <DEL> ΔιάγÏαψε τον χαÏακτήÏα ακÏιβώς Ï€Ïιν τον δείκτη
+ C-d ΔιάγÏαψε τον χαÏακτήÏα ακÏιβώς μετά τον δείκτη
+
+ M-<DEL> Εξαφάνισε την λέξη ακÏιβώς Ï€Ïιν τον δείκτη
+ M-d Εξαφάνισε την λέξη μετά τον δείκτη
+
+ C-k Εξαφάνισε από το σημείο του δείκτη ως το τέλος της γÏαμμής
+ M-k Εξαφάνισε ως το τέλος της παÏοÏσας Ï€Ïότασης
+
+ΠÏόσεξε πως το <DEL> και C-d σε σÏγκÏιση με M-<DEL> και M-d
+Ï€Ïοεκτείνουν την παÏάλληλο που άÏχισε με το C-f και M-f (κατ'ακÏίβεια,
+το <DEL> δεν είναι χαÏακτήÏας control, αλλά ας μην ανησυχοÏμε για
+αυτό). Τα C-k και M-k είναι κατά Ï„Ïόπο όπως το C-e και M-e καθώς οι
+γÏαμμές ταιÏιάζουν με τις Ï€Ïοτάσεις.
+
+ΜποÏείς επίσης να εξαφανίσεις ένα μέÏος κειμένου με ενιαίο Ï„Ïόπο.
+Κινήσου σε μία άκÏη του και πληκτÏολόγησε C-<SPC>. (<SPC> είναι το
+πλήκτÏο του κενοÏ.) Κατόπιν, μετακίνησε τον δείκτη στην άλλη άκÏη του
+κειμένου που θέλεις να εξαφανίσεις. Καθώς το κάνεις αυτό, το Emacs
+επισημαίνει το κείμενο Î¼ÎµÏ„Î±Î¾Ï Ï„Ï‰Î½ δÏο άκÏων του δείκτη και του σημείου
+όπου πληκτÏολόγησες C-<SPC>. Τέλος, πληκτÏολόγησε C-w. Αυτό
+εξαφανίζει το κείμενο Î¼ÎµÏ„Î±Î¾Ï Ï„Ï‰Î½ δÏο σημείων.
+
+>> Μετακίνησε τον δείκτη στο γÏάμμα Îœ στην αÏχή της Ï€ÏοηγοÏμενης
+ παÏαγÏάφου.
+>> ΠληκτÏολόγησε C-<SPC>. Το Emacs θα σου γÏάψει μήνυμα στο κάτω
+ μέÏος της οθόνης πως τέθηκε σημάδι («Mark set»).
+>> Μετακίνησε τον δείκτη στο κ της λέξης «άκÏη» στην δεÏτεÏη γÏαμμή
+ της παÏαγÏάφου.
+>> ΠληκτÏολόγησε C-w. Αυτό θα εξαφανίσει το κείμενο που άÏχιζε με Îœ
+ και τελειώνει ακÏιβώς Ï€Ïιν το κ.
+
+Η διαφοÏά Î¼ÎµÏ„Î±Î¾Ï Ï„Î·Ï‚ «εξαφάνισης» και της «διαγÏαφής» είναι πως το
+«εξαφανισμένο» κείμενο μποÏεί να επανεισαχθεί (σε οποιαδήποτε θέση),
+ενώ τα «διαγÏαμμένα» Ï€Ïάγματα δεν μποÏοÏν να επανεισαχθοÏν κατά αυτόν
+τον Ï„Ïόπο (μποÏείς, ωστόσο, να αναιÏέσεις την διαγÏαφή--δες παÏακάτω).
+Επανεισαγωγή εξαφανισμένου κειμένου ονομάζεται «τÏάβηγμα» («yanking»).
+(Φαντάσου πως Ï„Ïαβάς κάτι πίσω το οποίο είχε αφαιÏεθεί.) Γενικά, οι
+εντολές που αφαιÏοÏν Ï€Î¿Î»Ï ÎºÎµÎ¯Î¼ÎµÎ½Î¿ το εξαφανίζουν, ενώ οι εντολές που
+αφαιÏοÏν απλά ένα χαÏακτήÏα, ή μόνο κενές γÏαμμές ή κενά, κάνουν
+διαγÏαφή (οπότε δεν μποÏείς να τα Ï„Ïαβήξεις πίσω). <DEL> και C-d
+κάνουν διαγÏαφή στην απλή πεÏίπτωση, χωÏίς παÏάμετÏο. Αν τους δοθεί
+παÏάμετÏος, τότε κάνουν εξαφάνιση.
+
+>> Μετακίνησε τον δείκτη στην αÏχή μιας γÏαμμής που δεν είναι κενή.
+ Κατόπιν πληκτÏολόγησε C-k για να εξαφανίσεις το κείμενο ως το τέλος
+ της γÏαμμής.
+>> ΠληκτÏολόγησε C-k δεÏτεÏη φοÏά. Θα δεις πως εξαφανίζει τον
+ χαÏακτήÏα νέας γÏαμμής που ακολουθεί εκείνη την γÏαμμή.
+
+Σημείωσε πως ένα C-k εξαφανίζει το πεÏιεχόμενο της γÏαμμής, ενώ
+δεÏτεÏο C-k εξαφανίζει την ίδια την γÏαμμή και κάνει όλες τις
+ακόλουθες γÏαμμές να μετατοπιστοÏν Ï€Ïος τα πάνω. Το C-k εÏμηνεÏει την
+αÏιθμητική παÏάμετÏο με ειδικό Ï„Ïόπο: εξαφανίζει τις γÏαμμές ΚΑΙ το
+πεÏιεχόμενο τους. Αυτό δεν Ï€Ïόκειται για απλή επανάληψη. C-u 2 C-k
+εξαφανίζει δÏο γÏαμμές και τους αντίστοιχους χαÏακτήÏες νέας γÏαμμής·
+ενώ πληκτÏολογώντας το C-k δÏο φοÏές δεν θα το έκανε αυτό.
+
+ΜποÏείς να Ï„Ïαβήξεις εξαφανισμένο κείμενο στο ίδιο σημείο από όπου
+εξαφανίστηκε, ή σε κάποιο άλλο σημείο που επεξεÏγάζεσαι, ή ακόμα σε
+άλλο αÏχείο. ΜποÏείς να Ï„Ïαβήξεις το ίδιο κείμενο πολλές φοÏές· αυτό
+δημιουÏγεί πολλαπλά αντίγÏαφα του. Άλλοι κειμενογÏάφοι ονομάζουν την
+εξαφάνιση και το Ï„Ïάβηγμα «αποκοπή» και «επικόλληση» (δες το γλωσσάÏιο
+στο εγχειÏίδιο του Emacs).
+
+Η εντολή για Ï„Ïάβηγμα είναι C-y. Εισάγει το τελευταίο εξαφανισμένο
+κείμενο στην Ï„Ïέχουσα θέση του δείκτη.
+
+>> Δοκίμασε το· πληκτÏολόγησε C-y για τα Ï„Ïαβήξεις το κείμενο πίσω.
+
+Εάν κάνεις πολλά C-k στην σειÏά, όλο το εξαφανισμένο κείμενο
+αποθηκεÏεται μαζί, ώστε ένα C-y Ï„Ïαβάει όλες τις γÏαμμές συλλήβδην.
+
+>> Κάνε το Ï„ÏŽÏα· πληκτÏολόγησε C-k αÏκετές φοÏές.
+
+ΤώÏα ανάκτησε το εξαφανισμένο κείμενο:
+
+>> ΠληκτÏολόγησε C-y. Κατόπιν μετακίνησε τον δείκτη κάτω μεÏικές
+ γÏαμμές και πληκτÏολόγησε C-y ξανά. ΤώÏα βλέπεις πως να
+ αντιγÏάψεις οÏισμένο κείμενο.
+
+Τι κάνει εάν έχεις κείμενο που θέλεις να Ï„Ïαβήξεις πίσω και μετά να
+εξαφανίσεις κάτι άλλο; Το C-y θα Ï„Ïαβήξει την πιο Ï€Ïόσφατη εξαφάνιση.
+Αλλά η Ï€ÏοηγοÏμενη της δεν έχει χαθεί. ΜποÏείς να επιστÏέψεις σε αυτή
+χÏησιμοποιώντας την εντολή M-y. Î‘Ï†Î¿Ï Î­Ï‡ÎµÎ¹Ï‚ κάνει C-y για να πάÏεις
+την πιο Ï€Ïόσφατη εξαφάνιση, πληκτÏολογώντας το M-y αντικαθιστά το
+Ï„Ïαβηγμένο κείμενο με το λιγότεÏο Ï€Ïόσφατο εξαφανισμένο κείμενο.
+ΠληκτÏολογώντας M-y ξανά και ξανά επαναφέÏει ολοένα και παλαιότεÏες
+εξαφανίσεις. Όταν βÏεις το κείμενο που ψάχνεις, δεν χÏειάζεται να
+κάνεις κάτι άλλο για να το κÏατήσεις. Απλά συνέχισε την επεξεÏγασία,
+αφήνοντας το Ï„Ïαβηγμένο κείμενο εκεί που είναι.
+
+Εάν χÏησιμοποιήσεις το M-y αÏκετές φοÏές, θα επιστÏέψεις στο αÏχικό
+σημείο (την πιο Ï€Ïόσφατη εξαφάνιση).
+
+>> Εξαφάνισε μια γÏαμμή, κινήσου κάπου αλλοÏ, εξαφάνισε άλλη γÏαμμή.
+ Μετά πάτα C-y για να επαναφέÏεις την δεÏτεÏη εξαφανισμένη γÏαμμή.
+ Μετά κάνε M-y κι αυτή θα αντικατασταθεί με την Ï€Ïώτη εξαφανισμένη
+ γÏαμμή. Κάνε κι άλλα M-y να δεις τι θα σου βγάλει. Συνέχισε ώσπου
+ να σου δώσει πάλι την δεÏτεÏη εξαφανισμένη γÏαμμή. Αν θέλεις
+ μποÏείς να πεÏάσεις στο M-y θετικές ή αÏνητικές παÏαμέτÏους.
+
+
+* ΑÎΑΙΡΕΣΗ
+----------
+
+Εάν κάνεις αλλαγή στο κείμενο κι ÏστεÏα κÏίνεις πως ήταν λάθος,
+μποÏείς να την αναιÏέσεις με την εντολή αναίÏεσης C-/.
+
+Κανονικά, το C-/ αναιÏεί τις αλλαγές που επέφεÏε μία εντολή. Αν
+επαναλάβεις το C-/ πολλές φοÏές στη σειÏά, κάθε επανάληψη αναιÏεί
+ακόμα μία εντολή.
+
+Ωστόσο υπάÏχουν δÏο εξαιÏέσεις: εντολές που δεν Ï„ÏοποποιοÏν κείμενο
+δεν μετÏοÏν (όπως εντολές που κινοÏν τον δείκτη ή κυλοÏν το κείμενο)
+και χαÏακτήÏες που αυτό-εισάγονται συνήθως κÏίνονται ως ομάδες έως 20
+μέλη. (Αυτό είναι για να πεÏιοÏίσει τον αÏιθμό των C-/ που
+απαιτοÏνται για την αναίÏεση εισαγωγής κειμένου.)
+
+>> Εξαφάνισε αυτή την γÏαμμή με C-k και πληκτÏολόγησε C-/ ώστε να
+ επανεμφανιστεί.
+
+Το C-_ είναι εναλλακτική εντολή αναίÏεσης που λειτουÏγεί το ίδιο με το
+C-/. Σε οÏισμένους ακÏοδέκτες κειμένου, ενδέχεται να μην χÏειάζεται
+το shift για να εισάγεις το C-_. Σε οÏισμένους ακÏοδέκτες κειμένου,
+το C-/ στέλνει το σήμα του C-_ στο Emacs. Εναλλακτικά, το C-x u
+λειτουÏγεί ακÏιβώς όπως το C-/, αλλά είναι λίγο πιο δÏσκολο να το
+πληκτÏολογήσεις.
+
+Η αÏιθμητική παÏάμετÏος στα C-/, C-_, C-x u δÏα ως μετÏητής
+επανάληψης.
+
+ΜποÏείς να αναιÏέσεις την διαγÏαφή κειμένου κατά τον ίδιο Ï„Ïόπο που
+αναιÏείς την εξαφάνιση κειμένου. Ο διαχωÏισμός Î¼ÎµÏ„Î±Î¾Ï ÎµÎ¾Î±Ï†Î¬Î½Î¹ÏƒÎ·Ï‚ και
+διαγÏαφής έχει σημασία μόνο όταν θες να Ï„Ïαβήξεις κάτι πίσω με το C-y:
+δεν έχει καμιά διαφοÏά για τους σκοποÏÏ‚ της αναίÏεσης.
+
+
+* ΑΡΧΕΙΑ
+--------
+
+Για να καταστήσεις μόνιμο το κείμενο που επεξεÏγάζεσαι, Ï€Ïέπει να το
+βάλεις σε αÏχείο. Αλλιώς θα χαθεί όταν κλείσεις το Emacs. Για να
+βάλεις κείμενο σε αÏχείο, Ï€Ïέπει να το «βÏεις» Ï€Ïιν εισάγεις το
+κείμενο. (Η Ï€Ïάξη αυτή ονομάζεται επίσης ως «επίσκεψη» στην τοποθεσία
+του αÏχείου.)
+
+ΕξεÏÏεση του αÏχείο σημαίνει πως βλέπεις το πεÏιεχόμενο του εντός του
+Emacs. Κατά πολλοÏÏ‚ Ï„Ïόπους, είναι σαν να επεξεÏγάζεσαι το αÏχείο
+απευθείας. Ωστόσο, οι αλλαγές που κάνεις καθίστανται μόνιμες μόνο
+Î±Ï†Î¿Ï Â«Î±Ï€Î¿Î¸Î·ÎºÎµÏσεις» το αÏχείο. Αυτό γίνεται ώστε να μην μένουν
+μισοτελειωμένα αÏχεία στο σÏστημα ενάντια στην θέληση σου. Ακόμα κι
+αν αποθηκεÏσεις τις αλλαγές, το Emacs διατηÏεί αντίγÏαφο του γνησίου
+αÏχείου υπό ελαφÏÏŽÏ‚ Ï„Ïοποποιημένο όνομα, ώστε να μποÏείς να το
+επαναφέÏεις σε πεÏίπτωση που συνέβη κάποιο λάθος.
+
+Αν κοιτάξεις Ï€Ïος το κάτω μέÏος της οθόνης θα δεις μια γÏαμμή που
+αÏχίζει με παÏλες και αναφέÏει « -:--- TUTORIAL.el_GR» ή κάπως έτσι.
+Αυτό το μέÏος της οθόνης συνήθως δείχνει το όνομα του αÏχείου που
+επισκέπτεσαι. ΤώÏα επισκέπτεσαι το Ï€Ïοσωπικό σου αντίγÏαφο του
+κειμένου εκμάθησης του Emacs, που ονομάζεται «TUTORIAL.el_GR». Όταν
+βÏίσκεις ένα αÏχείο με το Emacs, το όνομα του θα εμφανιστεί σε εκείνο
+ακÏιβώς το σημείο.
+
+Μια ειδική πτυχή της εντολής για εξεÏÏεση αÏχείου είναι πως Ï€Ïέπει να
+Ï€ÏοσδιοÏίσεις ποιο αÏχείο θέλεις. Λέμε πως η εντολή «διαβάζει την
+παÏάμετÏο» (στην Ï€Ïοκειμένη πεÏίπτωση αυτή είναι το όνομα του
+αÏχείου). Î‘Ï†Î¿Ï Ï€Î»Î·ÎºÏ„Ïολογήσεις την εντολή
+
+ C-x C-f Î’Ïες ένα αÏχείο
+
+το Emacs θα σου ζητήσει να πληκτÏολογήσεις το όνομα του. Το όνομα
+του αÏχείου που εισάγεις εμφανίζεται στο κάτω μέÏος της οθόνης. Η
+τελευταία γÏαμμή ονομάζεται μικÏοαποσβεστήÏας (minibuffer) όταν
+χÏησιμοποιείται για τέτοιους σκοποÏÏ‚ εισαγωγής εντολής. ΜποÏείς να
+χÏησιμοποιήσεις τις κοινές εντολές του Emacs για επεξεÏγασία κειμένου
+καθώς γÏάφεις το όνομα του αÏχείου.
+
+Ενόσω δακτυλογÏαφείς το όνομα του αÏχείο (ή κάθε άλλο κείμενο στον
+μικÏοαποσβεστήÏα), μποÏείς να ακυÏώσεις την εντολή με το C-g.
+
+>> ΠληκτÏολόγησε C-x C-f και μετά C-g. Αυτό ακυÏώνει τον
+ μικÏοαποσβεστήÏα και την εντολή C-x C-f που τον χÏησιμοποιοÏσε.
+ Συνεπώς δεν θα βÏεις κανένα αÏχείο.
+
+Όταν ολοκληÏώσεις την εισαγωγή του ονόματος ενός αÏχείου, πάτα
+<Return> για να την επικυÏώσεις. Ο μικÏοαποσβεστήÏας εξαφανίζεται
+καθώς το C-x C-f αναλαμβάνει δÏάση για να βÏει το αÏχείο που του
+ÏŒÏισες.
+
+Το πεÏιεχόμενο του αÏχείου Ï„ÏŽÏα εμφανίζεται στην οθόνη και μποÏείς να
+το επεξεÏγαστείς. Όταν θέλεις να μονιμοποιήσεις τις αλλαγές που
+έκανες, χÏησιμοποίησε την εντολή
+
+ C-x C-s Αποθήκευσε το αÏχείο
+
+Αυτή αντιγÏάφει το κείμενο που βÏίσκεται στο Emacs στο εν λόγω αÏχείο.
+Την Ï€Ïώτη φοÏά που το κάνεις αυτό, το Emacs μετονομάζει το γνήσιο ώστε
+να μην χαθεί. Το νέο όνομα πεÏιέχει το σÏμβολο «~» ως κατάληξη του
+αÏÏ‡Î¹ÎºÎ¿Ï Î¿Î½ÏŒÎ¼Î±Ï„Î¿Ï‚. Όταν ολοκληÏωθεί η αποθήκευση, το Emacs παÏουσιάζει
+το όνομα του αÏχείου όπου γÏάφτηκαν οι αλλαγές.
+
+>> ΠληκτÏολόγησε C-x C-s TUTORIAL.el_GR <Return>.
+ Αυτό θα αποθηκεÏσει αυτό το κείμενο σε αÏχείο με το όνομα
+ TUTORIAL.el_GR και θα αναφέÏει πως έγÏαψε σε αυτό στο κάτω μέÏος
+ της οθόνης.
+
+ΜποÏείς να βÏεις υφιστάμενο αÏχείο είτε για να το δεις ή να το
+επεξεÏγαστείς. ΜποÏείς επίσης να βÏεις αÏχείο το οποίο δεν
+Ï€ÏοϋπάÏχει. Έτσι το Emacs θα δημιουÏγήσει το αÏχείο: θα βÏεις το νέο
+αÏχείο, το οποίο είναι κενό, και κατόπιν θα εισάγεις κείμενο σε αυτό.
+Όταν επιχειÏήσεις να το αποθηκεÏσεις, το Emacs θα δημιουÏγήσει το
+αÏχείο αυτό με το πεÏιεχόμενο που του έδωσες. Από εκεί και πέÏα
+θεώÏησε πως επεξεÏγάζεσαι ένα υφιστάμενο αÏχείο.
+
+
+* ΑΠΟΣΒΕΣΤΗΡΕΣ
+--------------
+
+Εάν βÏεις δεÏτεÏο αÏχείο με το C-x C-f, το Ï€Ïώτο παÏαμένει εντός του
+Emacs. ΜποÏείς να επανέλθεις σε αυτό αν το ξαναβÏείς με το C-x C-f.
+Έτσι δÏναται να έχεις πολλά αÏχεία ανοιχτά εντός του Emacs.
+
+Το Emacs αποθηκεÏει το πεÏιεχόμενο του κάθε αÏχείου σε αντικείμενο το
+οποίο ονομάζεται «αποσβεστήÏας» (buffer). Η εξεÏÏεση αÏχείου
+δημιουÏγεί νέο αποσβεστήÏα εντός του Emacs. Για να δεις την λίστα με
+όλους τους υφιστάμενους αποσβεστήÏες, πληκτÏολόγησε
+
+ C-x C-b ΠαÏάθεσε αποσβεστήÏες
+
+>> Δοκίμασε το C-x C-b Ï„ÏŽÏα.
+
+ΠαÏατήÏησε πως κάθε αποσβεστήÏας έχει όνομα ενώ δÏναται να έχει επίσης
+κι όνομα αÏχείου του οποίο το πεÏιεχόμενο κÏατεί. ΟΤΙΔΗΠΟΤΕ βλέπεις
+σε παÏάθυÏο Emacs πάντα είναι μέÏος ενός αποσβεστήÏα.
+
+>> ΠληκτÏολόγησε C-x 1 για να εξαφανίσεις το παÏάθυÏο που παÏαθέτει
+ τους αποσβεστήÏες.
+
+Όταν έχεις πολλοÏÏ‚ αποσβεστήÏες, μόνο ένας είναι ο «τÏέχον» σε κάθε
+στιγμή. ΠÏόκειται για τον αποσβεστήÏα που επεξεÏγάζεσαι. Εάν θες να
+επεξεÏγαστείς κάποιον άλλο αποσβεστήÏα, Ï€Ïέπει να «μεταβείς» σε αυτόν.
+Αν θα μεταβείς σε αποσβεστήÏας που επισκέπτεται αÏχείο, μποÏείς να το
+κάνεις με το C-x C-f Ï€ÏοσδιοÏίζοντας το όνομα του αÏχείου. Αλλά
+υπάÏχει ευκολότεÏος Ï„Ïόπος: χÏησιμοποίησε την εντολή C-x b. Σε αυτή
+την εντολή, Ï€Ïέπει να εισάγεις το όνομα του αποσβεστήÏα.
+
+>> ΔημιοÏÏγησε αÏχείο ονόματι «foo»: γÏάψε C-x C-f foo <Return>.
+ Μετά πληκτÏολόγησε C-x b TUTORIAL.el_GR <Return> για να επιστÏέψεις
+ σε αυτό το κείμενο εκμάθησης του Emacs.
+
+Συνήθως, το όνομα του αποσβεστήÏα αντιστοιχεί σε αυτό του αÏχείου
+(χωÏίς το μέÏος του αÏχείου που αναφέÏει τον κατάλογο/φάκελο στον
+οποίο βÏίσκεται). Ωστόσο αυτό δεν ισχÏει πάντοτε. Η παÏάθεση
+αποσβεστήÏων που φτιάχνει το C-x C-b δείχνει τόσο το όνομα του
+αποσβεστήÏα όσο κι αυτό του αÏχείου.
+
+Κάποιοι αποσβεστήÏες δεν ανταποκÏίνονται σε αÏχεία. Ο αποσβεστήÏας
+ονόματι «*Buffer List*», που πεÏιέχει τα στοιχεία του C-x C-b, δεν
+έχει κάποιο υποκείμενο αÏχείο. Ο αποσβεστήÏας Î±Ï…Ï„Î¿Ï Ï„Î¿Ï…
+TUTORIAL.el_GR αÏχικά δεν είχε κάποιο αÏχείο, αλλά Ï„ÏŽÏα έχει, καθώς
+στην Ï€ÏοηγοÏμενη ενότητα χÏησιμοποίησες το C-x C-s για να τον
+αποθηκεÏσεις σε αÏχείο.
+
+Ο αποσβεστήÏας με το όνομα «*Messages*» επίσης δεν έχει αÏχείο. Αυτός
+πεÏιέχει όλα τα μηνÏματα που εμφανίζονται στο κάτω μέÏος της οθόνης
+κατά την λειτουÏγία του Emacs.
+
+>> ΠληκτÏολόγησε C-x b *Messages* <Return> για να δεις τον αποσβεστήÏα
+ με τα μηνÏματα. Μετά πληκτÏολόγησε C-x b TUTORIAL.el_GR <Return>
+ για να επανέλθεις εδώ.
+
+Εάν κάνεις αλλαγές στο κείμενο ενός αÏχείου, μετά βÏεις κάποιο άλλο
+αÏχείο, η Ï€Ïάξη αυτή δεν αποθηκεÏει τις αλλαγές που έκανες στο Ï€Ïώτο
+αÏχείο. Οι αλλαγές παÏαμένουν εντός του Emacs, στον αποσβεστήÏα που
+ανταποκÏίνεται σε εκείνο το αÏχείο. Η δημιουÏγία ή επεξεÏγασία του
+δεÏτεÏου αÏχείου δεν επηÏεάζει το Ï€Ïώτο. Αυτό είναι Ï€Î¿Î»Ï Ï‡Ïήσιμο,
+ωστόσο σημαίνει πως χÏειάζεσαι έναν βολικό Ï„Ïόπο να αποθηκεÏεις
+αλλαγές σε πολλοÏÏ‚ αποσβεστήÏες. Το να Ï€Ïέπει να επιστÏέψεις στο
+Ï€Ïώτο αÏχείο απλά και μόνο για να το αποθηκεÏσεις είναι ενοχλητικό.
+Οπότε έχουμε
+
+ C-x s Αποθήκευσε οÏισμένους αποσβεστήÏες στα αÏχεία τους
+
+Το C-x s Ïωτά για κάθε αποσβεστήÏα που επισκέπτεται αÏχείο και που
+κÏατά αλλαγές οι οποίες δεν έχουν αποθηκευτεί. Σε Ïωτά για κάθε
+αποσβεστήÏα κατά πόσον να αποθηκευτοÏν οι αλλαγές του στο αÏχείο.
+
+>> Εισήγαγε μια γÏαμμή κειμένου και πληκτÏολόγησε C-x s.
+ Θα σε Ïωτήσει κατά πόσον θες να αποθηκεÏσεις τον αποσβεστήÏα με
+ όνομα TUTORIAL.el_GR. Απάντα καταφατικά με το «y» (yes).
+
+
+* ΕΠΕΚΤΕΙÎΟÎΤΑΣ ΤΟ ΣΥÎΟΛΟ ΕÎΤΟΛΩÎ
+---------------------------------
+
+ΥπάÏχουν πάÏα πολλές εντολές του Emacs που δεν μποÏοÏν να χωÏέσουν σε
+όλους τους control και meta χαÏακτήÏες. Το Emacs ξεπεÏνά αυτό το
+εμπόδιο με την εντολή επέκτασης (eXtend). Αυτή έχει δÏο μοÏφές:
+
+ C-x ΧαÏακτήÏος επέκταση. Ακολουθείται από τον χαÏακτήÏα.
+ M-x Ονόματος επέκταση. Ακολουθείται από όνομα.
+
+Αυτές είναι εντολές που είναι χÏήσιμες εν γένει αλλά χÏησιμοποιοÏνται
+σχετικά λιγότεÏο από αυτές που έμαθες έως Ï„ÏŽÏα. Έχεις ήδη δει εντολές
+επέκτασης, όπως το C-x C-f και το C-x C-s. Άλλο παÏάδειγμα είναι η
+εντολή που κλείνει το Emacs--αυτή είναι C-x C-c. (Μην ανησυχείς για
+απώλεια αλλαγών που έκανες· το C-x C-c Ïωτά να αποθηκεÏσει αλλαγές σε
+κάθε αÏχείο Ï€Ïιν τεÏματίσει το Emacs.)
+
+Εάν χÏησιμοποιείς γÏαφική Ï€Ïοβολή, δεν χÏειάζεσαι κάποια ειδική εντολή
+για να μεταβείς από το Emacs σε κάποια άλλη εφαÏμογή. ΜποÏείς να το
+κάνεις με το ποντίκι ή τις εντολές του διαχειÏιστή παÏαθÏÏων. Αν όμως
+χÏησιμοποιείς ακÏοδέκτη κειμένου ο οποίος Ï€Ïοβάλει μόνο μία εφαÏμογή,
+τότε Ï€Ïέπει να «αναστείλεις» το Emacs για να επιλέξεις οποιαδήποτε
+άλλη εφαÏμογή.
+
+C-z είναι η εντολή της *Ï€ÏοσωÏινής* εξόδου από το Emacs--μποÏείς να
+επιστÏέψεις στην ίδια συνεδÏία υστεÏότεÏα. Όταν το Emacs λειτουÏγεί
+εντός ακÏοδέκτη κειμένου, το C-z «αναστέλλει» το Emacs· δηλαδή
+επιστÏέφει στο πεÏίβλημα (shell) χωÏίς να καταστÏέψει την εÏγασία του
+Emacs. Στα πλείστα πεÏιβλήματα, μποÏείς να επαναφέÏεις το Emacs με
+την εντολή «fg» ή την «%emacs».
+
+ΧÏησιμοποιείς το C-x C-c όταν θες να αποσυνδεθείς πλήÏως. Είναι η
+σωστή Ï€Ïάξη για έξοδο από το Emacs, παÏάδειγμα για πεÏιπτώσεις ταχείας
+επεξεÏγασίας κειμένου όπως στην διαχείÏιση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου.
+
+ΥπάÏχουν πολλές εντολές του Ï„Ïπου C-x. ΠαÏαθέτουμε αυτές που έμαθες:
+
+ C-x C-f ΕξεÏÏεση αÏχείου
+ C-x C-s Αποθήκευση αποσβεστήÏα σε αÏχείο
+ C-x s Αποθήκευση μεÏικών αποσβεστήÏων στα αÏχεία τους
+ C-x C-b ΠαÏάθεση αποσβεστήÏων
+ C-x b Μετάβαση σε αποσβεστήÏα
+ C-x C-c Έξοδος από το Emacs
+ C-x 1 ΔιαγÏαφή όλων πλην ενός παÏαθÏÏου
+ C-x u ΑναίÏεση
+
+Επώνυμες εκτεταμένες εντολές είναι αυτές που χÏησιμοποιοÏνται με
+λιγότεÏη συχνότητα, ή εντολές που χÏησιμοποιοÏνται μόνο σε
+συγκεκÏιμένες λειτουÏγίες. Ως παÏάδειγμα έχουμε την εντολή
+replace-string, η οποία αντικαθιστά μια σειÏά (αλληλουχία) χαÏακτήÏων
+με μια άλλη εντός του αποσβεστήÏα. Όταν πληκτÏολογείς M-x, το Emacs
+σε Ï€ÏοτÏέπει στο κάτω μέÏος της οθόνης για το όνομα της εντολής·
+«replace-string» σε αυτή την πεÏίπτωση. Απλά να πληκτÏολογήσεις το
+«repl s<TAB>» και το Emacs θα ολοκληÏώσει το όνομα. (<TAB> αναφέÏεται
+στο πλήκτÏο Tab, που συνήθως βÏίσκεται πάνω από το Caps Lock ή το
+Shift στην αÏιστεÏή πλευÏά του πληκτÏολογίου.) Κατάθεσε το όνομα της
+εντολής με το <Return>.
+
+Η εντολή replace-string απαιτεί δÏο παÏαμέτÏους--την σειÏά χαÏακτήÏων
+Ï€Ïος αντικατάσταση και αυτή που θα την αντικαταστήσει. Κάθε
+παÏάμετÏος τελειώνει με το <Return>.
+
+>> Μετακίνησε τον δείκτη στην κενή γÏαμμή δÏο γÏαμμές κάτω από αυτήν.
+ ΠληκτÏολόγησε M-x repl s<Return>αλλάξει<Return>μετατÏαπεί<Return>
+
+ ΠÏόσεξε πως αυτή η γÏαμμή έχει αλλάξει: αντικατέστησες την λέξη
+ «αλλάξει» με την «μετατÏαπεί» όπου αυτή υπήÏχε μετά την αÏχική θέση
+ του δείκτη.
+
+
+* ΑΥΤΟΜΑΤΗ ΑΠΟΘΗΚΕΥΣΗ
+---------------------
+
+Όταν έχεις κάνει αλλαγές σε ένα αÏχείο, αλλά δεν τις έχεις αποθηκεÏσει
+ακόμα, ενδέχεται να χαθοÏν αν ο υπολογιστής κλείσει. Για να σε
+Ï€Ïοστατέψει από αυτό το ενδεχόμενο, το Emacs κατά διαστήματα γÏάφει σε
+ένα αÏχείο «αυτόματης αποθήκευσης» κάθε αÏχείο που επεξεÏγάζεσαι. Το
+όνομα Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… αÏχείου έχει ένα # στην αÏχή κι ένα στο τέλος· για
+παÏάδειγμα, αν το αÏχείο σου ονομάζεται «hello.c», η αυτόματη
+αποθήκευση γίνεται στο «#hello.c#». Όταν αποθηκεÏσεις το αÏχείο με
+τον φυσιολογικό Ï„Ïόπο, το Emacs διαγÏάφει το αÏχείο αυτόματης
+αποθήκευσης.
+
+Εάν ο υπολογιστής κλείσει αναπάντεχα μποÏείς να ανακτήσεις αυτό που
+επεξεÏγαζόσουν με το να βÏεις το αÏχείο (το κανονικό αÏχείο, όχι αυτό
+της αυτόματης αντιγÏαφής του) και να πληκτÏολογήσεις M-x
+recover-this-file <Return>. Όταν σου ζητηθεί επιβεβαίωση,
+πληκτÏολόγησε yes<Return> για την ανάκτηση των δεδομένων.
+
+
+* ΤΟΠΟΣ ΑÎΤΗΧΗΣΗΣ
+-----------------
+
+Αν το Emacs διακÏίνει πως πληκτÏολογείς τους χαÏακτήÏες μιας
+μακÏοσκελοÏÏ‚ εντολής με σχετικά αÏγό Ïυθμό, θα σου τους δείξει στο
+κάτω μέÏος της οθόνης σε αυτό που ονομάζεται «τόπος αντήχησης». Ο
+τόπος αντήχησης πεÏιλαμβάνει την τελευταία γÏαμμή της οθόνης.
+
+
+* ΓΡΑΜΜΗ ΚΑΤΑΣΤΑΣΗΣ
+-------------------
+
+Η γÏαμμή ακÏιβώς πάνω από τον τόπο αντήχησης ονομάζεται «γÏαμμή
+κατάστασης». Αυτή αναφέÏει πληÏοφοÏίες όπως:
+
+ -:**- TUTORIAL.el_GR 63% L800 (Fundamental)
+
+Αυτή η γÏαμμή έχει χÏήσιμες πληÏοφοÏίες για την κατάσταση του Emacs
+και του κειμένου που επεξεÏγάζεσαι.
+
+Ήδη γνωÏίζεις τι σημαίνει το πεδίο ονόματος του αÏχείου--αναφέÏει το
+αÏχείο που έχεις επισκεφθεί. Το ÎÎ% δείχνει την Ï„Ïέχουσα θέση σου
+στον αποσβεστήÏα του κειμένου: σημαίνει πως ÎΠεπί τις εκατό του
+αποσβεστήÏα βÏίσκεται πέÏα από το πάνω μέÏος της οθόνης. Εάν το πάνω
+μέÏος πεÏιέχει όλο το Ï€ÏοηγοÏμενο κείμενο, τότε θα γÏάφει «Top» αντί
+για «0%». Αν είναι στο κάτω μέÏος του αποσβεστήÏα, τότε θα αναγÏάφει
+«Bot». Αν ο αποσβεστήÏας είναι μικÏός ώστε όλο το πεÏιεχόμενο του να
+χωÏάει στην οθόνη, τότε η γÏαμμή κατάστασης θα γÏάφει «All».
+
+Το L και τα ψηφία δείχνουν την θέση με άλλο Ï„Ïόπο: τον αÏιθμό της
+γÏαμμής όπου βÏίσκεται το σημείο.
+
+Οι αστεÏίσκοι κοντά στην αÏχή δείχνουν πως έχουν υπάÏξει Ï„Ïοποποιήσεις
+στο κείμενο. Μόλις επισκεφθείς ή αποθηκεÏσεις ένα αÏχείο, εκείνο το
+τμήμα δεν δείχνει αστεÏίσκους παÏά μόνο παÏλες.
+
+Το τμήμα της γÏαμμής κατάστασης εντός παÏενθέσεων αναφέÏει τις
+λειτουÏγίες επεξεÏγασίας που ισχÏουν. Η βασική λειτουÏγία ονομάζεται
+Fundamental κι είναι αυτή που χÏησιμοποιείς Ï„ÏŽÏα. ΠÏόκειται για
+παÏάδειγμα «αξιωματικής λειτουÏγίας» (major mode).
+
+Το Emacs έχει πολλές αξιωματικές λειτουÏγίες. Κάποιες αφοÏοÏν την
+επεξεÏγασία κειμένου σε διάφοÏες γλώσσες Ï€ÏογÏÎ±Î¼Î¼Î±Ï„Î¹ÏƒÎ¼Î¿Ï Î® για διάφοÏα
+ήδη κειμένου, όπως Lisp mode, Text mode, κτλ. Μόνο μια αξιωματική
+λειτουÏγία γίνεται να είναι σε ισχÏ, και το όνομα της βÏίσκεται στην
+γÏαμμή κατάστασης όπου Ï„ÏŽÏα υπάÏχει το «Fundamental».
+
+Κάθε αξιωματική λειτουÏγία κάνει κάποιες εντολές να συμπεÏιφέÏονται με
+διαφοÏετικό Ï„Ïόπο. Για παÏάδειγμα, υπάÏχουν εντολές για την
+δημιουÏγία σχολίων σε ένα Ï€ÏόγÏαμμα, και καθώς κάθε γλώσσα έχει τις
+δικές τις ιδέες για το τι συνιστά σχόλιο, η εκάστοτε αξιωματική
+λειτουÏγία εισάγει σχόλια ιδιοτÏόπως.
+
+Κάθε αξιωματική λειτουÏγία φέÏει το όνομα μιας εκτεταμένης εντολής,
+που είναι ένας Ï„Ïόπος να αλλάξεις σε αυτή. Για παÏάδειγμα, M-x
+fundamental-mode είναι η εντολή που θέτει σε Î¹ÏƒÏ‡Ï Ï„Î¿ Fundamental mode.
+
+Αν θα επεξεÏγάζεσαι κείμενο σε ανθÏώπινη γλώσσα, όπως αυτό το αÏχείο,
+μάλλον θες να χÏησιμοποιήσεις το Text mode.
+
+>> ΠληκτÏολόγησε M-x text-mode <Return>.
+
+Μην ανησυχείς, καθώς καμία από τις εντολές που έχεις μάθει δεν αλλάζει
+με ουσιαστικό Ï„Ïόπο. Ωστόσο θα διαπιστώσεις πως M-f και M-b Ï„ÏŽÏα
+θεωÏοÏν τα εισαγωγικά ως μέÏος της λέξης. ΠÏιν, στο Fundamental mode,
+M-f και M-b διάβαζαν τα εισαγωγικά ως διαχωÏιστικά λέξεων.
+
+Αξιωματικές λειτουÏγίες κάνουν τέτοιες εκλεπτυσμένες αλλαγές: οι
+πλείστες εντολές «διεκπεÏαιώνουν το ίδιο έÏγο» σε κάθε αξιωματική
+λειτουÏγία, αλλά ίσως το επιτυγχάνουν με ελαφÏÏŽÏ‚ διαφοÏετικό Ï„Ïόπο.
+
+Για να μάθεις πεÏισσότεÏα σχετικά με την Ï„Ïέχουσα αξιωματική
+λειτουÏγία, πληκτÏολόγησε C-h m.
+
+>> Μετακίνησε τον δείκτη στην γÏαμμή μετά από αυτήν.
+>> ΠληκτÏολόγησε C-l C-l ώστε να έÏθει αυτή η γÏαμμή στο πάνω μέÏος
+ της οθόνης.
+>> ΠληκτÏολόγησε C-h m για να διαβάσεις πως διαφέÏει το Text mode από
+ το Fundamental mode.
+>> ΠληκτÏολόγησε C-x 1 για να αφαιÏέσεις την καταγÏαφή από την οθόνη.
+
+Οι αξιωματικές λειτουÏγίες ονομάζονται έτσι διότι υπάÏχουν και οι
+ελάσσονες λειτουÏγίες (minor modes). Ελάσσονες λειτουÏγίες δεν
+υποκαθιστοÏν τις αξιωματικές λειτουÏγίες, παÏά μόνο επί μέÏους πτυχές
+τους. Κάθε ελάσσων λειτουÏγία μποÏεί να ενεÏγοποιηθεί ή
+απενεÏγοποιηθεί αυτοτελώς, ανεξάÏτητα από άλλες ελάσσονες λειτουÏγίες
+ή οποιονδήποτε συνδυασμό τους.
+
+Μια ελάσσων λειτουÏγία που είναι Ï€Î¿Î»Ï Ï‡Ïήσιμη, ειδικά για την
+επεξεÏγασία κειμένου ανθÏώπινης γλώσσας, είναι η Auto Fill mode. Όταν
+αυτή η λειτουÏγία ενεÏγοποιηθεί, το Emacs αυτόματα διαχωÏίζει τις
+γÏαμμές Î¼ÎµÏ„Î±Î¾Ï Ï„Ï‰Î½ λέξεων όταν αυτές γίνονται Ï€Î¿Î»Ï Ï€Î»Î±Ï„Î¹Î­Ï‚.
+
+Το Auto Fill mode ενεÏγοποιείται με M-x auto-fill-mode <Return>. Όταν
+η λειτουÏγία είναι σε ισχÏ, μποÏεί να απενεÏγοποιηθεί πάλι με M-x
+auto-fill-mode <Return>. Αν είναι απενεÏγοποιημένη, τότε η εντολή
+αυτή την ενεÏγοποιεί, και το αντίστÏοφο. Λέμε πως η εντολή
+«εναλλάσσει την λειτουÏγία».
+
+>> ΠληκτÏολόγησε M-x auto-fill-mode <Return> Ï„ÏŽÏα. Κατόπιν
+ πληκτÏολόγησε μια γÏαμμή με «ασδφ » πολλές φοÏές ως που να δεις ότι
+ διαιÏείται σε δÏο γÏαμμές. ΠÏέπει να έχει κενά Î¼ÎµÏ„Î±Î¾Ï Ï„Ï‰Î½
+ χαÏακτήÏων, διότι μόνο με βάση αυτά λειτουÏγεί το Auto Fill (δεν
+ κόβει λέξεις).
+
+Το μήκος συνήθως οÏίζεται στους 70 χαÏακτήÏες, αλλά μποÏείς να το
+αλλάξεις με την εντολή C-x f. ÎŒÏισε τον αÏιθμό που επιθυμείς ως
+αÏιθμητική παÏάμετÏο.
+
+>> ΠληκτÏολόγησε C-x f με παÏάμετÏο το 20. (C-u 2 0 C-x f). Κατόπιν
+ πληκτÏολόγησε τυχαίο κείμενο με κενά και Ï€Ïόσεξε πως το Emacs
+ συμπληÏώνει τις γÏαμμές έως τους 20 χαÏακτήÏες. Μετά θέσε πάλι το
+ μήκος τους 70 χαÏακτήÏες χÏησιμοποιώντας C-x f με αÏιθμητική
+ παÏάμετÏο.
+
+Αν κάνεις αλλαγές στην μέση της παÏαγÏάφου, το Auto Fill mode δεν
+επανασυμπληÏώνει για χάÏη σου.
+Για να επανασυμπληÏώσεις μια παÏάγÏαφο χειÏοκίνητα, πληκτÏολόγησε M-q
+(META-q) με τον δείκτη εντός της παÏαγÏάφου εκείνης.
+
+>> Μετακίνησε τον δείκτη στην Ï€ÏοηγοÏμενη παÏάγÏαφο και πληκτÏολόγησε
+ M-q.
+
+
+* ΑÎΑΖΗΤΗΣΗ
+-----------
+
+Το Emacs μποÏεί να αναζητήσει σειÏές (σειÏά (string) είναι αλληλουχία
+χαÏακτήÏων) είτε Ï€Ïος τα εμπÏός είτε ανάποδα. Αναζήτηση σειÏάς
+συνιστά κίνηση του δείκτη· μετακινεί τον δείκτη όπου εμφανίζεται η
+σειÏά.
+
+Η εντολή αναζήτησης του Emacs είναι «τμηματική». Αυτό σημαίνει πως η
+αναζήτηση γίνεται ενόσω δακτυλογÏαφείς τους χαÏακτήÏες της σειÏάς που
+αναζητείς.
+
+Η εντολή Ï€Ïος εκκίνηση αναζήτησης είναι C-s για κίνηση Ï€Ïος τα εμπÏός
+και C-r και κίνηση όπισθεν. ΑΛΛΑ ΠΕΡΙΜΕÎΕ! Μην τις δοκιμάσεις ακόμα.
+
+Όταν πληκτÏολογείς C-s θα δεις πως η σειÏά «I-search» εμφανίζεται ως
+Ï€ÏοτÏοπή στον τόπο αντήχησης. Αυτό σου λέει πως το Emacs βÏίσκεται σε
+αυτό που ονομάζεται «τμηματική αναζήτηση» και πεÏιμένει να
+πληκτÏολογήσεις αυτό το οποίο ψάχνεις. <Return> ολοκληÏώνει την
+αναζήτηση.
+
+>> ΤώÏα πληκτÏολόγησε C-s για να αÏχίσεις την αναζήτηση. ΑΡΓΑ, ένα
+ γÏάμμα τη φοÏά, γÏάψε «δείκτη», κάνοντας παÏση Î±Ï†Î¿Ï ÎµÎ¹ÏƒÎ¬Î³ÎµÎ¹Ï‚ τον
+ κάθε χαÏακτήÏα για να δεις τι συμβαίνει με τον δείκτη.
+ ΤώÏα έχεις αναζητήσει για «δείκτη» μία φοÏά.
+>> Πάτα πάλι C-s για να ψάξεις την επόμενη εμφάνιση του «δείκτη».
+>> ΤώÏα πληκτÏολόγησε <DEL> τέσσεÏις φοÏές και δες πως κινείται ο
+ δείκτης.
+>> ΠληκτÏολόγησε <Return> για να τεÏματίσεις την αναζήτηση.
+
+Είδες τι έγινε; Το Emacs, σε τμηματική αναζήτηση, Ï€Ïοσπαθεί να
+εντοπίσει την επόμενη εμφάνιση της σειÏάς χαÏακτήÏων που έγÏαψες. Για
+να μεταφεÏθείς στην επόμενη εμφάνιση, πάτα C-s ξανά. Εάν δεν υπάÏχει
+άλλη, το Emacs θα σηματοδοτήσει «αποτυχία» (failing). Το C-g μποÏεί
+να τεÏματίσει την αναζήτηση.
+
+Κατά την διάÏκεια μιας τμηματικής αναζήτησης εάν πατήσεις <DEL>, η
+αναζήτηση «υποχωÏεί» σε Ï€ÏότεÏο σημείο. Αν πατήσεις <DEL> αμέσως
+αφότου έχεις πληκτÏολογήσει C-s για μετακίνηση στην επόμενη εμφάνιση
+μιας σειÏάς χαÏακτήÏων, θα μεταβείς πίσω στην Ï€ÏοηγοÏμενη εμφάνιση.
+Εάν δεν υπάÏχει Ï€ÏοηγοÏμενη εμφάνιση, το <DEL> διαγÏάφει τον τελευταίο
+χαÏακτήÏα στην σειÏά. Για παÏάδειγμα, φαντάσου πως έγÏαψες «δ» για να
+βÏεις την Ï€Ïώτη εμφάνιση του. ΤώÏα αν Ï€Ïοσθέσεις το «ε» θα πας στην
+Ï€Ïώτη εμφάνιση του «δε». ΤώÏα πάτα <DEL>. ΔιαγÏάφει το «ε» από την
+σειÏά και μετακινεί τον δείκτη πίσω στην Ï€Ïώτη εμφάνιση του «δ».
+
+Αν είσαι στο μέσον μιας αναζήτησης και πληκτÏολογήσεις ένα χαÏακτήÏα
+control ή meta (με κάποιες εξαιÏέσεις--όπως C-s και C-r που έχουν
+ειδική σημασία στην αναζήτηση), η αναζήτηση θα τεÏματιστεί.
+
+Το C-s ξεκινά αναζήτηση που ψάχνει για κάθε εμφάνιση της αναζητοÏμενης
+σειÏάς ΑΠΟ την Ï„Ïέχουσα θέση του δείκτη. Εάν θες να βÏεις
+Ï€ÏοηγοÏμενες εμφανίσεις, χÏησιμοποίησε το C-r. Όσα είπαμε για το C-s
+ισχÏουν για το C-r, με μόνη διαφοÏά την κατεÏθυνση της αναζήτησης.
+
+
+* ΠΟΛΛΑΠΛΑ ΠΑΡΑΘΥΡΑ
+-------------------
+
+Ένα από τα καλά του Emacs είναι πως μποÏείς να παÏουσιάσεις πέÏαν του
+ενός παÏαθÏÏου στην οθόνη. (Σημείωσε πως το Emacs χÏησιμοποιεί τον
+ÏŒÏο «πλαίσιο» (frame)--επεξηγείται στην επόμενη ενότητα--για αυτό που
+οÏισμένες εφαÏμογές αποκαλοÏν «παÏάθυÏο» (window). Το εγχειÏίδιο του
+Emacs πεÏιέχει γλωσσάÏιο με όλους τους ÏŒÏους.)
+
+>> ΦέÏε τον δείκτη σε αυτή την γÏαμμή και πληκτÏολόγησε C-l C-l.
+
+>> ΤώÏα πάτα C-x 2, που μοιÏάζει την οθόνη σε δÏο παÏάθυÏα.
+ Και τα δÏο παÏάθυÏα παÏουσιάζουν αυτή την εκμάθηση. Ο δείκτης
+ επεξεÏγασίας παÏαμένει στο πάνω παÏάθυÏο.
+
+>> ΠληκτÏολόγησε C-M-v για να κυλήσεις το κάτω παÏάθυÏο. (Εάν δεν
+ έχεις META ή ALT πλήκτÏο, τότε πληκτÏολόγησε <ESC> C-v.)
+
+>> ΠληκτÏολόγησε C-x o («o» είναι για το «άλλο» στην αγγλική (other))
+ ώστε να επιλέξεις το έτεÏο παÏάθυÏο.
+
+>> ΧÏησιμοποίησε C-v και M-v στο κάτω παÏάθυÏο για να το κυλήσεις.
+ Συνέχισε να διαβάζεις αυτές τις οδηγίες στο πάνω παÏάθυÏο.
+
+>> Πάτα C-x o και πάλι ώστε να φέÏεις τον δείκτη πίσω στο πάνω
+ παÏάθυÏο. Ο δείκτης στο πάνω παÏάθυÏο είναι εκεί που ήταν και
+ Ï€Ïιν.
+
+ΜποÏείς να συνεχίσεις να χÏησιμοποιείς C-x o για εναλλαγή Î¼ÎµÏ„Î±Î¾Ï Ï„Ï‰Î½
+παÏαθÏÏων. Το «επιλεγμένο παÏάθυÏο», όπου γίνεται η επεξεÏγασία,
+είναι αυτό που έχει ένα φανεÏÏŒ δείκτη που αναβοσβήνει καθώς γÏάφεις.
+Τα άλλα παÏάθυÏα έχουν τις δικές τους θέσεις για τον δείκτη· αν
+χÏησιμοποιείς γÏαφική Ï€Ïοβολή του Emacs, αυτοί οι δείκτες
+παÏουσιάζονται ως άδεια κουτιά που δεν αναβοσβήνουν.
+
+Η εντολή C-M-v είναι Ï€Î¿Î»Ï Ï‡Ïήσιμη όταν επεξεÏγάζεται κείμενο σε ένα
+παÏάθυÏο και χÏησιμοποιείς το έτεÏο παÏάθυÏο για αναφοÏά. ΧωÏίς να
+φÏγεις από το επιλεγμένο παÏάθυÏο, μποÏείς να κυλήσεις το παÏάθυÏο με
+C-M-v.
+
+Το C-M-v αποτελεί παÏάδειγμα CONTROL-META χαÏακτήÏα. Αν έχεις META (ή
+ALT) πλήκτÏο, πληκτÏολογείς C-M-v κÏατώντας πατημένα τόσο το CONTROL
+όσο και το META και πληκτÏολογώντας v. Δεν έχει σημασία αν το CONTROL
+ή το META «έÏχεται Ï€Ïώτο», καθώς αμφότεÏα μεταβάλουν τον χαÏακτήÏα που
+εισάγεις.
+
+Αν δεν έχεις το πλήκτÏο META (ή ALT), και χÏησιμοποιείς το <ESC>, τότε
+η σειÏά έχει σημασία: Ï€Ïώτα πατάς κι αφήνεις το <ESC> κι ακολουθείς με
+CONTROL-v, διότι CONTROL-<ESC>-v δεν θα δουλέψει. Αυτό γιατί το <ESC>
+είναι χαÏακτήÏας από μόνο του, κι όχι πλήκτÏο μετατÏοπής χαÏακτήÏων.
+
+>> ΠληκτÏολόγησε C-x 1 στο πάνω παÏάθυÏο για να κλείσεις το κάτω
+ παÏάθυÏο.
+
+(Άν πατοÏσες C-x 1 στο κάτω παÏάθυÏο, θα έκλεινες το πάνω. Φαντάσου
+πως αυτή η εντολή λέει «κÏάτα ένα παÏάθυÏο--αυτό που έχω επιλεγμένο.»)
+
+Δεν είναι απαÏαίτητο να παÏουσιάζεις τον ίδιο αποσβεστήÏα σε πολλά
+παÏάθυÏα. Αν χÏησιμοποιήσεις το C-x C-f για να βÏεις ένα αÏχείο στο
+ένα παÏάθυÏο, το έτεÏο παÏάθυÏο δεν αλλάζει. ΜποÏείς να βÏεις ένα
+αÏχείο σε κάθε παÏάθυÏο ανεξάÏτητα από τα άλλα.
+
+Î™Î´Î¿Ï Î¬Î»Î»Î¿Ï‚ ένα Ï„Ïόπος για να χÏησιμοποιείς δÏο παÏάθυÏα που δείχνουν
+διαφοÏετικά Ï€Ïάγματα:
+
+>> ΠληκτÏολόγησε C-x 4 C-f και δώσε όνομα αÏχείου στην σχετική
+ Ï€ÏοτÏοπή που εμφανίζεται στο κάτω μέÏος της οθόνης. ΕπικÏÏωσε την
+ επιλογή σου με το <Return>. Δες πως το επιλεγμένο αÏχείο
+ εμφανίζεται στο κάτω παÏάθυÏο. Ο δείκτης πάει κι αυτός εκεί.
+
+>> ΠληκτÏολόγησε C-x o για να επιστÏέψεις στο πάνω παÏάθυÏο και μετά
+ C-x 1 για να κλείσεις το κάτω παÏάθυÏο.
+
+
+* ΠΟΛΛΑΠΛΑ ΠΛΑΙΣΙΑ
+------------------
+
+Το Emacs μποÏεί επίσης να δημιουÏγήσει πολλά «πλαίσια». Πλαίσιο
+ονομάζουμε αυτό που πεÏιέχει ένα ή πεÏισσότεÏα παÏάθυÏα, μαζί με τα
+μενοÏ, μπάÏες κÏλισης, τόπο αντήχησης, κτλ. Σε γÏαφικές Ï€Ïοβολές,
+αυτό που το Emacs αποκαλεί «πλαίσιο» είναι το ίδιο που άλλες εφαÏμογές
+ονομάζουν «παÏάθυÏο». Πολλά γÏαφικά πλαίσια μποÏοÏν να εμφανίζονται
+στην οθόνη ταυτόχÏονα. Σε ακÏοδέκτη κειμένου, μόνο ένα πλαίσιο μποÏεί
+να παÏουσιάζεται κάθε φοÏά.
+
+>> ΠληκτÏολόγησε C-x 5 2.
+ Δες ένα νέο πλαίσιο που εμφανίστηκε στην οθόνη.
+
+ΜποÏείς να κάνεις όσα έκανες στο αÏχικό πλαίσιο και στο νέο πλαίσιο.
+Δεν υπάÏχει τίποτα το ειδικό για το ένα ή το άλλο.
+
+>> ΠληκτÏολόγησε C-x 5 0.
+ Αυτό αφαιÏεί το επιλεγμένο πλαίσιο.
+
+ΜποÏείς πάντοτε να αφαιÏέσεις ένα πλαίσιο με τον κοινό Ï„Ïόπο που
+Ï€ÏοσφέÏει το σÏστημα γÏαφικών (συνήθως πατάς με το ποντίκι πάνω σε ένα
+εικονίδιο «X» σε ένα από τα πάνω άκÏα του πλαισίου). Αν αφαιÏέσεις το
+τελευταίο πλαίσιο της λειτουÏγίας του Emacs κατά αυτόν τον Ï„Ïόπο, τότε
+κλείνει το Emacs.
+
+
+* ΕΠΙΠΕΔΑ ΑÎΑΔΡΟΜΙΚΗΣ ΕΠΕΞΕΡΓΑΣΙΑΣ
+----------------------------------
+
+Κάποιες φοÏές θα βÏεθείς σε αυτό που ονομάζουμε «επίπεδο αναδÏομικής
+επεξεÏγασίας». Αυτό επισημαίνεται από αγκÏλες στην γÏαμμή κατάστασης
+που πεÏιβάλλουν τις παÏενθέσεις γÏÏω από την αξιωματική λειτουÏγία.
+Για παÏάδειγμα, ίσως δεις [(Fundamental)] αντί για (Fundamental).
+
+Για να βγεις από επίπεδο αναδÏομικής επεξεÏγασίας, πληκτÏολόγησε <ESC>
+<ESC> <ESC>. Αυτή είναι η γενική εντολή εξόδου. ΜποÏείς να την
+χÏησιμοποιήσεις για να κλείσεις όλα τα έτεÏα παÏάθυÏα και για να βγεις
+από τον μικÏοαποσβεστήÏα.
+
+>> ΠληκτÏολόγησε M-x για να μπεις στον μικÏοαποσβεστήÏα· κατόπιν πάτα
+ <ESC> <ESC> <ESC> για να εξέλθεις.
+
+Δεν μποÏείς να χÏησιμοποιήσεις C-g για να βγεις από επίπεδο
+αναδÏομικής επεξεÏγασίας. Αυτό είναι έτσι γιατί το C-g ακυÏώνει
+εντολές ή τις παÏαμέτÏους αυτών ΕÎΤΟΣ του Ï„Ïέχοντος επιπέδου
+αναδÏομικής επεξεÏγασίας.
+
+
+* ΠΕΡΙΣΣΟΤΕΡΗ ΒΟΗΘΕΙΑ
+---------------------
+
+Σε αυτό τον οδηγό Ï€Ïοσπαθήσαμε να Ï€ÏοσφέÏουμε βασικές γνώσεις για να
+αÏχίσεις να χÏησιμοποιείς το Emacs. ΥπάÏχουν τόσα πολλά στο Emacs που
+θα ήταν αδÏνατο να τα εξηγήσουμε όλα εδώ. Ωστόσο, μάλλον θα θέλεις να
+μάθεις πεÏισσότεÏα για τις διάφοÏες δυνατότητες που παÏέχει το Emacs.
+ΠÏος αυτόν τον σκοπό, το Emacs Ï€ÏοσφέÏει εντολές για την εξεÏÏεση κι
+ανάγνωση οδηγιών. Αυτές οι εντολές «βοήθειας» (help) όλες αÏχίζουν με
+τον χαÏακτήÏα CONTROL-h, που αποκαλείται «ο χαÏακτήÏας βοηθείας».
+
+Για να χÏησιμοποιήσεις τις υπηÏεσίες βοηθείας, πληκτÏολόγησε C-h, και
+μετά ένα χαÏακτήÏα που ανταποκÏίνεται στο είδος της βοήθειας που
+επιζητείς. Αν είσαι σε ΠΡΑΓΜΑΤΙΚΑ δÏσκολη θέση, πάτα C-h ? και το
+Emacs θα σου πει τι είδη βοηθείας υπάÏχουν. Αν έχεις ήδη πατήσει C-h
+και αποφάσισες πως δεν θέλεις καμία βοήθεια, απλά ακÏÏωσε το με C-g.
+
+(Αν το C-h δεν Ï€Ïοβάλει μήνυμα για βοήθεια στο κάτω μέÏος της οθόνης,
+δοκίμασε το πλήκτÏο F1, αλλιώς M-x help <Return>.)
+
+Η πιο βασική βοήθεια Ï€ÏοσφέÏεται από το C-h c. ΠληκτÏολόγησε C-h,
+ÏστεÏα το c, και μετά τον χαÏακτήÏα ή αλληλουχία χαÏακτήÏων
+οποιασδήποτε εντολής: το Emacs θα εμφανίσει μια σÏντομη πεÏιγÏαφή της
+εντολής.
+
+>> ΠληκτÏολόγησε C-h c C-p
+
+Το μήνυμα θα είναι κάπως έτσι:
+
+ C-p εκτελεί την εντολή previous-line
+
+Αυτό σου λέει το «όνομα της συνάÏτησης». Καθώς οι συναÏτήσεις έχουν
+ονόματα που φανεÏώνουν την λειτουÏγία τους, μποÏοÏν να εÏμηνευθοÏν κι
+ως Ï€Î¿Î»Ï ÏƒÏντομες πεÏιγÏαφές--επαÏκείς για να σου υπενθυμίσουν κάτι που
+ήδη έχεις μάθει.
+
+Εντολές με πολλοÏÏ‚ χαÏακτήÏες, όπως C-x C-s ή <ESC>v (αντί του M-v για
+όσους δεν έχουν πλήκτÏο META ή ALT) μποÏοÏν κι αυτές να δοθοÏν μετά το
+C-h c.
+
+Για πεÏισσότεÏες πληÏοφοÏίες αναφοÏικά με μια εντολή, χÏησιμοποίησε το
+C-h k αντί του C-h c.
+
+>> ΠληκτÏολόγησε C-h k C-p.
+
+Αυτό δείχνει την πλήÏη καταγÏαφή της συνάÏτησης, καθώς και το όνομα
+της, σε νέο παÏάθυÏο του Emacs. Όταν το διαβάσεις, πάτα C-x 1 για να
+κλείσεις εκείνο το παÏάθυÏο. Δεν χÏειάζεται να το κάνεις αυτό αμέσως.
+Ίσως θες Ï€Ïώτα να επεξεÏγαστείς κάτι καθώς αναφέÏεσαι στο κείμενο
+βοηθείας και μετά να πληκτÏολογήσεις C-x 1.
+
+Î™Î´Î¿Ï Î¬Î»Î»ÎµÏ‚ χÏήσιμες επιλογές με το C-h:
+
+ C-h x ΠεÏιέγÏαψε μια εντολή. Ζητά το όνομα της εντολής.
+
+>> ΠÏοσπάθησε C-h x previous-line <Return>.
+ Δείχνει όλες τις πληÏοφοÏίες που έχει το Emacs σχετικά με την
+ συνάÏτηση που δίνει την εντολή C-p.
+
+ΠαÏόμοια εντολή είναι αυτή του C-h v που δείχνει την καταγÏαφή μιας
+μεταβλητής, συμπεÏιλαμβανομένων αυτών που μποÏείς να Ï„Ïοποποιήσεις για
+να αλλάξεις την συμπεÏιφοÏά του Emacs. ΠÏέπει να γÏάψεις το όνομα της
+μεταβλητής στην σχετική Ï€ÏοτÏοπή.
+
+ C-h a Συναφή εντολών (command apropos). ΓÏάψε μια
+ λέξη-κλειδί και το Emacs θα παÏαθέσει όλες τις εντολές
+ των οποίων το όνομα πεÏιέχει αυτήν την λέξη. Όλες
+ αυτές οι εντολές μποÏοÏν να κληθοÏν με το META-x. Για
+ οÏισμένες εντολές, τα συναφή εντολών πεÏιέχουν και την
+ σχετική αλληλουχία χαÏακτήÏων που εκτελεί την εντολή.
+
+>> ΠληκτÏολόγησε C-h a file <Return>.
+
+Αυτό παÏαθέτει σε έτεÏο παÏάθυÏο όλες τις εντολές M-x που πεÏιέχουν
+τον ÏŒÏο «file» στο όνομα τους. Θα δεις εντολές χαÏακτήÏος Î¼ÎµÏ„Î±Î¾Ï Ï„Ï‰Î½
+επονομαζομένων (όπως C-x C-f πέÏιξ του find-file).
+
+>> ΠληκτÏολόγησε C-M-v για να κυλήσεις το παÏάθυÏο βοηθείας. Κάνε το
+ μεÏικές φοÏές.
+
+>> ΠληκτÏολόγησε C-x 1 για να κλείσεις το παÏάθυÏο βοηθείας.
+
+ C-h i Διάβασε τα εγχειÏίδια (Info manuals). Αυτή η εντολή
+ σε βάζει σε ειδικό αποσβεστήÏα που ονομάζεται «*info*»
+ όπου μποÏείς να διαβάσεις εγχειÏίδια για τις
+ συσκευασίες που είναι εγκατεστημένες στο σÏστημα σου.
+ ΠληκτÏολόγησε m emacs <Return> για να διαβάσεις το
+ εγχειÏίδιο του Emacs. Αν δεν έχεις χÏησιμοποιήσει το
+ Info ποτέ, πληκτÏολόγησε h και το Emacs θα σου δείξει
+ τις σχετικές λειτουÏγίες. Î‘Ï†Î¿Ï Î¿Î»Î¿ÎºÎ»Î·Ïώσεις αυτή την
+ εκμάθηση, να αναφέÏεσε στο εγχειÏίδιο του Emacs ως την
+ κÏÏια πηγή όλων των καταγÏαφών.
+
+
+* ΑΛΛΕΣ ΛΕΙΤΟΥΡΓΙΕΣ
+-------------------
+
+ΜποÏείς να μάθεις πεÏισσότεÏα για το Emacs διαβάζοντας το εγχειÏίδιο
+του, είτε ως έντυπο βιβλίο, είτε εντός του Emacs (χÏησιμοποίησε τον
+κατάλογο βοηθείας ή πληκτÏολόγησε C-h r). ΔÏο λειτουÏγίες που ίσως να
+σου φανοÏν χÏήσιμες είναι η «ολοκλήÏωση», που εξοικονομεί στην
+δακτυλογÏάφηση, και το Dired, που απλοποιεί την διαχείÏιση αÏχείων.
+
+Η ολοκλήÏωση είναι Ï„Ïόπος αποφυγής αχÏείαστης πληκτÏολόγησης. Για
+παÏάδειγμα, αν θες να μεταβείς στον αποσβεστήÏα *Messages*,
+πληκτÏολογείς C-x b *M<Tab> και το Emacs θα συμπληÏώσει το υπόλοιπο
+του ονόματος ως εκεί που μποÏεί να κÏίνει αντιστοιχία με αυτό που
+έχεις ήδη γÏάψει. Η ολοκλήÏωση δουλεÏει επίσης για ονόματα εντολών κι
+αÏχείων. Στο εγχειÏίδιο καταγÏάφεται στην ενότητα «Completion».
+
+Το Dired σου επιτÏέπει να παÏαθέτεις κατάλογο αÏχείων (και Ï€ÏοαιÏετικά
+υποκαταλόγους), να επιλέγεις, επισκέπτεσαι, μετονομάζεις, διαγÏάφεις,
+ή γενικά να επιδÏάς πάνω σε αÏχεία. Το Dired καταγÏάφεται στο
+εγχειÏίδιο στην ενότητα «Dired».
+
+Το εγχειÏίδιο καταγÏάφει πολλές άλλες λειτουÏγίες του Emacs.
+
+
+* ΕΓΚΑΤΑΣΤΑΣΗ ΣΥΣΚΕΥΑΣΙΩÎ
+-------------------------
+
+ΥπάÏχει πλοÏσιος όγκος συσκευασιών (packages) του Emacs που έχουν
+παÏασκευαστεί από την κοινότητα των χÏηστών του, που επεκτείνουν τις
+δυνατότητες του Emacs. Αυτές οι συσκευασίες πεÏιλαμβάνουν υποστήÏιξη
+για νέες γλώσσες, Ï€Ïόσθετα θέματα χÏωμάτων, Ï€Ïοεκτάσεις για εξωτεÏικές
+εφαÏμογές, και άλλα πολλά.
+
+Για παÏάθεση των διαθέσιμων συσκευασιών, πληκτÏολόγησε M-x
+list-packages. Στη σχετική λίστα, μποÏείς να εγκαταστήσεις ή
+απεγκαταστήσεις συσκευασίες, καθώς και να διαβάσεις τις πεÏιγÏαφές
+τους. Για πεÏισσότεÏες πληÏοφοÏίες πεÏί διαχείÏισης συσκευασιών, δες
+το εγχειÏίδιο του Emacs.
+
+
+* ΚΑΤΑΛΗΚΤΙΚΑ
+-------------
+
+Για έξοδο από το Emacs, χÏησιμοποίησε C-x C-c.
+
+Αυτή η εκμάθηση γÏάφτηκε για να είναι κατανοητή σε όλους τους νέους
+χÏήστες. Αν λοιπόν κάτι παÏαμένει ασαφές, μην κάτσεις εκεί να
+κατηγοÏείς τον εαυτό σου - πες μας για το Ï€Ïόβλημα σου!
+
+
+* ΑÎΤΙΓΡΑΦΗ
+-----------
+
+Αυτό το κείμενο εκμάθησης είναι συνέχεια μιας μακÏάς γÏαμμής κειμένων
+εκμάθησης του Emacs, αÏχής γενομένης Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… Stuart Cracraft για το
+αÏχικό Emacs.
+
+Αυτή η έκδοση της εκμάθησης είναι μέÏος του GNU Emacs. Έχει
+πνευματικά δικαιώματα και δίνεται με την άδεια διανομής αντιγÏάφων υπό
+κάποιους ÏŒÏους.
+
+ Πνευματικά Δικαιώματα (C) 1985, 1996, 1998, 2001-2022 Free Software
+ Foundation, Inc.
+
+ Αυτό το αÏχείο είναι μέÏος του GNU Emacs.
+
+ Το GNU Emacs είναι ελεÏθεÏο λογισμικό: μποÏείτε να το αναδιανέμετε
+ ή/και να το Ï„Ïοποποιήσετε σÏμφωνα με τους ÏŒÏους της GNU Γενική
+ Δημόσια Άδεια (GNU General Public License) όπως δημοσιεÏθηκε από το
+ ΊδÏυμα ΕλεÏθεÏου Î›Î¿Î³Î¹ÏƒÎ¼Î¹ÎºÎ¿Ï (Free Software Foundation), είτε την
+ έκδοση 3 της άδειας, είτε (κατά την επιλογή σας) οποιαδήποτε
+ μεταγενέστεÏη έκδοση.
+
+ Το GNU Emacs διανέμεται με την ελπίδα πως θα είναι χÏήσιμο, αλλά
+ ΧΩΡΙΣ ΚΑΜΙΑ ΕΓΓΥΗΣΗ· χωÏίς καν την συνεπαγόμενη εγγÏηση της
+ ΕΜΠΟΡΕΥΣΙΜΟΤΗΤΑΣ ή ΚΑΤΑΛΛΗΛΟΤΗΤΑΣ ΓΙΑ ΣΥΓΚΕΚΡΙΜΕÎΟ ΣΚΟΠΟ. Δείτε την
+ GNU Γενική Δημόσια Άδεια (GNU General Public License) για
+ πεÏισσότεÏες λεπτομέÏειες.
+
+ Οφείλατε να λάβετε αντίγÏαφο της GNU Γενικής Δημόσιας Άδειας (GNU
+ General Public License) μαζί με το GNU Emacs. Εάν όχι, δείτε
+ <https://www.gnu.org/licenses/>.
+
+ΠαÏακαλώ όπως διαβάσετε το αÏχείο COPYING και δώσετε αντίγÏαφα του GNU
+Emacs στους φίλους σας. Βοηθήστε στην καταπολέμηση του πεÏιοÏισμοÏ
+(«ιδιοκτησία») του Î»Î¿Î³Î¹ÏƒÎ¼Î¹ÎºÎ¿Ï Î´Î¹Î± της χÏήσης, γÏαφής, και κοινοποίησης
+ελεÏθεÏου λογισμικοÏ!
diff --git a/etc/tutorials/TUTORIAL.translators b/etc/tutorials/TUTORIAL.translators
index b6b95787068..891b6a16824 100644
--- a/etc/tutorials/TUTORIAL.translators
+++ b/etc/tutorials/TUTORIAL.translators
@@ -26,6 +26,10 @@ Maintainer: Dale Gulledge <dsplat@rochester.rr.com>
Author: Rafael Sepúlveda <drs@gnulinux.org.mx>
Maintainer: Rafael Sepúlveda <drs@gnulinux.org.mx>
+* TUTORIAL.el_GR:
+Author: Protesilaos Stavrou <info@protesilaos.com>
+Maintainer: Protesilaos Stavrou <info@protesilaos.com>
+
* TUTORIAL.fr:
Author: Éric Jacoboni <jaco@teaser.fr>
Maintainer: Éric Jacoboni <jaco@teaser.fr>
diff --git a/lib/cdefs.h b/lib/cdefs.h
index cb2514504f1..7b8ed5b344b 100644
--- a/lib/cdefs.h
+++ b/lib/cdefs.h
@@ -164,13 +164,13 @@
|| (__builtin_constant_p (__l) && (__l) > 0))
/* Length is known to be safe at compile time if the __L * __S <= __OBJSZ
- condition can be folded to a constant and if it is true. The -1 check is
- redundant because since it implies that __glibc_safe_len_cond is true. */
+ condition can be folded to a constant and if it is true, or unknown (-1) */
#define __glibc_safe_or_unknown_len(__l, __s, __osz) \
- (__glibc_unsigned_or_positive (__l) \
- && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \
- __s, __osz)) \
- && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz))
+ ((__osz) == (__SIZE_TYPE__) -1 \
+ || (__glibc_unsigned_or_positive (__l) \
+ && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \
+ (__s), (__osz))) \
+ && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), (__s), (__osz))))
/* Conversely, we know at compile time that the length is unsafe if the
__L * __S <= __OBJSZ condition can be folded to a constant and if it is
diff --git a/lib/libc-config.h b/lib/libc-config.h
index 8fec4893787..a56665b1ce3 100644
--- a/lib/libc-config.h
+++ b/lib/libc-config.h
@@ -121,6 +121,7 @@
# undef __attr_dealloc
# undef __attr_dealloc_free
# undef __attribute__
+# undef __attribute_alloc_align__
# undef __attribute_alloc_size__
# undef __attribute_artificial__
# undef __attribute_const__
@@ -129,6 +130,7 @@
# undef __attribute_format_arg__
# undef __attribute_format_strfmon__
# undef __attribute_malloc__
+# undef __attribute_maybe_unused__
# undef __attribute_noinline__
# undef __attribute_nonstring__
# undef __attribute_pure__
@@ -142,16 +144,24 @@
# undef __extern_always_inline
# undef __extern_inline
# undef __flexarr
+# undef __fortified_attr_access
# undef __fortify_function
# undef __glibc_c99_flexarr_available
+# undef __glibc_fortify
+# undef __glibc_fortify_n
# undef __glibc_has_attribute
# undef __glibc_has_builtin
# undef __glibc_has_extension
+# undef __glibc_likely
# undef __glibc_macro_warning
# undef __glibc_macro_warning1
# undef __glibc_objsize
# undef __glibc_objsize0
+# undef __glibc_safe_len_cond
+# undef __glibc_safe_or_unknown_len
# undef __glibc_unlikely
+# undef __glibc_unsafe_len
+# undef __glibc_unsigned_or_positive
# undef __inline
# undef __ptr_t
# undef __restrict
@@ -159,6 +169,7 @@
# undef __va_arg_pack
# undef __va_arg_pack_len
# undef __warnattr
+# undef __wur
/* Include our copy of glibc <sys/cdefs.h>. */
# include <cdefs.h>
diff --git a/lib/md5.h b/lib/md5.h
index 5b92eac5ec8..611c230b817 100644
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -24,6 +24,9 @@
#include <stdint.h>
# if HAVE_OPENSSL_MD5
+# ifndef OPENSSL_API_COMPAT
+# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
+# endif
# include <openssl/md5.h>
# endif
diff --git a/lib/regcomp.c b/lib/regcomp.c
index b607c85320f..122c3de58c3 100644
--- a/lib/regcomp.c
+++ b/lib/regcomp.c
@@ -2038,15 +2038,25 @@ peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
}
switch (c)
{
- case '-':
- token->type = OP_CHARSET_RANGE;
- break;
case ']':
token->type = OP_CLOSE_BRACKET;
break;
case '^':
token->type = OP_NON_MATCH_LIST;
break;
+ case '-':
+ /* In V7 Unix grep and Unix awk and mawk, [...---...]
+ (3 adjacent minus signs) stands for a single minus sign.
+ Support that without breaking anything else. */
+ if (! (re_string_cur_idx (input) + 2 < re_string_length (input)
+ && re_string_peek_byte (input, 1) == '-'
+ && re_string_peek_byte (input, 2) == '-'))
+ {
+ token->type = OP_CHARSET_RANGE;
+ break;
+ }
+ re_string_skip_bytes (input, 2);
+ FALLTHROUGH;
default:
token->type = CHARACTER;
}
diff --git a/lib/sha1.h b/lib/sha1.h
index 098678d8da6..bc3470a508d 100644
--- a/lib/sha1.h
+++ b/lib/sha1.h
@@ -23,6 +23,9 @@
# include <stdint.h>
# if HAVE_OPENSSL_SHA1
+# ifndef OPENSSL_API_COMPAT
+# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
+# endif
# include <openssl/sha.h>
# endif
diff --git a/lib/sha256.h b/lib/sha256.h
index dc9d87e615f..533173a59e8 100644
--- a/lib/sha256.h
+++ b/lib/sha256.h
@@ -22,6 +22,9 @@
# include <stdint.h>
# if HAVE_OPENSSL_SHA256
+# ifndef OPENSSL_API_COMPAT
+# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
+# endif
# include <openssl/sha.h>
# endif
diff --git a/lib/sha512.h b/lib/sha512.h
index f38819faf0f..1eb18702278 100644
--- a/lib/sha512.h
+++ b/lib/sha512.h
@@ -22,6 +22,9 @@
# include "u64.h"
# if HAVE_OPENSSL_SHA512
+# ifndef OPENSSL_API_COMPAT
+# define OPENSSL_API_COMPAT 0x10101000L /* FIXME: Use OpenSSL 1.1+ API. */
+# endif
# include <openssl/sha.h>
# endif
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index d52c2f79638..a86643c3ca3 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -184,7 +184,11 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
# undef free
# define free rpl_free
# endif
+# if defined __cplusplus && (__GLIBC__ + (__GLIBC_MINOR__ >= 14) > 2)
+_GL_FUNCDECL_RPL (free, void, (void *ptr) throw ());
+# else
_GL_FUNCDECL_RPL (free, void, (void *ptr));
+# endif
_GL_CXXALIAS_RPL (free, void, (void *ptr));
# else
_GL_CXXALIAS_SYS (free, void, (void *ptr));
diff --git a/lib/string.in.h b/lib/string.in.h
index b6840fa9121..33160b25254 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -583,7 +583,7 @@ _GL_FUNCDECL_RPL (strndup, char *,
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
_GL_CXXALIAS_RPL (strndup, char *, (char const *__s, size_t __n));
# else
-# if !@HAVE_DECL_STRNDUP@ || __GNUC__ >= 11
+# if !@HAVE_DECL_STRNDUP@ || (__GNUC__ >= 11 && !defined strndup)
_GL_FUNCDECL_SYS (strndup, char *,
(char const *__s, size_t __n)
_GL_ARG_NONNULL ((1))
@@ -593,7 +593,7 @@ _GL_CXXALIAS_SYS (strndup, char *, (char const *__s, size_t __n));
# endif
_GL_CXXALIASWARN (strndup);
#else
-# if __GNUC__ >= 11
+# if __GNUC__ >= 11 && !defined strndup
/* For -Wmismatched-dealloc: Associate strndup with free or rpl_free. */
_GL_FUNCDECL_SYS (strndup, char *,
(char const *__s, size_t __n)
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 83ab61b28b5..d8c4b480359 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -832,6 +832,7 @@ since it could result in memory overflow and make Emacs crash."
(scroll-bar-adjust-thumb-portion windows boolean "24.4")
(x-scroll-event-delta-factor mouse float "29.1")
(x-gtk-use-native-input keyboard boolean "29.1")
+ (x-dnd-disable-motif-drag dnd boolean "29.1")
;; xselect.c
(x-select-enable-clipboard-manager killing boolean "24.1")
;; xsettings.c
@@ -870,6 +871,8 @@ since it could result in memory overflow and make Emacs crash."
((or (equal "scroll-bar-adjust-thumb-portion"
(symbol-name symbol))
(equal "x-scroll-event-delta-factor"
+ (symbol-name symbol))
+ (equal "x-dnd-disable-motif-drag"
(symbol-name symbol)))
(featurep 'x))
((string-match "\\`x-" (symbol-name symbol))
diff --git a/lisp/dabbrev.el b/lisp/dabbrev.el
index 220a2f52e92..b04128cf677 100644
--- a/lisp/dabbrev.el
+++ b/lisp/dabbrev.el
@@ -225,18 +225,27 @@ or matched by `dabbrev-ignored-buffer-regexps'."
(defcustom dabbrev-ignored-buffer-names '("*Messages*" "*Buffer List*")
"List of buffer names that dabbrev should not check.
-See also `dabbrev-ignored-buffer-regexps'."
+See also `dabbrev-ignored-buffer-regexps' and
+`dabbrev-ignored-buffer-modes'."
:type '(repeat (string :tag "Buffer name"))
:group 'dabbrev
:version "20.3")
(defcustom dabbrev-ignored-buffer-regexps nil
"List of regexps matching names of buffers that dabbrev should not check.
-See also `dabbrev-ignored-buffer-names'."
+See also `dabbrev-ignored-buffer-names' and
+`dabbrev-ignored-buffer-modes'."
:type '(repeat regexp)
:group 'dabbrev
:version "21.1")
+(defcustom dabbrev-ignored-buffer-modes '(archive-mode image-mode)
+ "Inhibit looking for abbreviations in buffers derived from these modes.
+See also `dabbrev-ignored-buffer-names' and
+`dabbrev-ignored-buffer-regexps'."
+ :type '(repeat symbol)
+ :version "29.1")
+
(defcustom dabbrev-check-other-buffers t
"Should \\[dabbrev-expand] look in other buffers?
nil: Don't look in other buffers.
@@ -383,6 +392,14 @@ If the prefix argument is 16 (which comes from \\[universal-argument] \\[univers
then it searches *all* buffers."
(interactive "*P")
(dabbrev--reset-global-variables)
+ (setq dabbrev--check-other-buffers (and arg t))
+ (setq dabbrev--check-all-buffers
+ (and arg (= (prefix-numeric-value arg) 16)))
+ (let ((completion-at-point-functions '(dabbrev-capf)))
+ (completion-at-point)))
+
+(defun dabbrev-capf ()
+ "Dabbrev completion function for `completion-at-point-functions'."
(let* ((abbrev (dabbrev--abbrev-at-point))
(beg (progn (search-backward abbrev) (point)))
(end (progn (search-forward abbrev) (point)))
@@ -420,10 +437,7 @@ then it searches *all* buffers."
(t
(mapcar #'downcase completion-list)))))))
(complete-with-action a list s p)))))
- (setq dabbrev--check-other-buffers (and arg t))
- (setq dabbrev--check-all-buffers
- (and arg (= (prefix-numeric-value arg) 16)))
- (completion-in-region beg end table)))
+ (list beg end table)))
;;;###autoload
(defun dabbrev-expand (arg)
@@ -632,19 +646,29 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
"Return a list of other buffers to search for a possible abbrev.
The current buffer is not included in the list.
-This function makes a list of all the buffers returned by `buffer-list',
-then discards buffers whose names match `dabbrev-ignored-buffer-names'
-or `dabbrev-ignored-buffer-regexps'. It also discards buffers for which
-`dabbrev-friend-buffer-function', if it is bound, returns nil when called
-with the buffer as argument.
-It returns the list of the buffers that are not discarded."
+This function makes a list of all the buffers returned by
+`buffer-list', then discards buffers whose names match
+`dabbrev-ignored-buffer-names' or
+`dabbrev-ignored-buffer-regexps', and major modes that match
+`dabbrev-ignored-buffer-modes'. It also discards buffers for
+which `dabbrev-friend-buffer-function', if it is bound, returns
+nil when called with the buffer as argument. It returns the list
+of the buffers that are not discarded."
(dabbrev-filter-elements
- buffer (buffer-list)
+ buffer (dabbrev--filter-buffer-modes)
(and (not (eq (current-buffer) buffer))
(not (dabbrev--ignore-buffer-p buffer))
(boundp 'dabbrev-friend-buffer-function)
(funcall dabbrev-friend-buffer-function buffer))))
+(defun dabbrev--filter-buffer-modes ()
+ (seq-filter (lambda (buffer)
+ (not (apply
+ #'provided-mode-derived-p
+ (buffer-local-value 'major-mode buffer)
+ dabbrev-ignored-buffer-modes)))
+ (buffer-list)))
+
(defun dabbrev--try-find (abbrev reverse n ignore-case)
"Search for ABBREV, backwards if REVERSE, N times.
If IGNORE-CASE is non-nil, ignore case while searching.
@@ -779,7 +803,7 @@ of the start of the occurrence."
(setq list
(append list
(dabbrev-filter-elements
- buffer (buffer-list)
+ buffer (dabbrev--filter-buffer-modes)
(and (not (memq buffer list))
(not (dabbrev--ignore-buffer-p buffer)))))))
;; Remove the current buffer.
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index ae033618c24..d2bac5c467c 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -1264,7 +1264,8 @@ and `dired-compress-files-alist'."
(when (zerop
(dired-shell-command
(format-spec (cdr rule)
- `((?o . ,(shell-quote-argument out-file))
+ `((?o . ,(shell-quote-argument
+ (file-local-name out-file)))
(?i . ,(mapconcat
(lambda (in-file)
(shell-quote-argument
@@ -3292,7 +3293,7 @@ type \\[help-command] at that time.
Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
If you exit the query-replace loop (\\[keyboard-quit], RET or q), you can
-resume the query replace with the command \\[tags-loop-continue]."
+resume the query replace with the command \\[fileloop-continue]."
(interactive
(let ((common
(query-replace-read-args
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index 8a76eaf58cf..54cac116168 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -825,7 +825,6 @@ Interactively, COUNT is the prefix numeric argument, and defaults to 1."
,@body))
(put ',prev-sym 'definition-name ',base))))
-
(provide 'easy-mmode)
;;; easy-mmode.el ends here
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 74ffeb166d4..0b8078579cc 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -5,7 +5,7 @@
;; Author: Noah Friedman <friedman@splode.com>
;; Keywords: extensions
;; Created: 1995-10-06
-;; Version: 1.11.1
+;; Version: 1.12.0
;; Package-Requires: ((emacs "26.3"))
;; This is a GNU ELPA :core package. Avoid functionality that is not
@@ -464,19 +464,22 @@ directly from the user or from ElDoc's automatic mechanisms'.")
(defvar eldoc--doc-buffer-docs nil "Documentation items in `eldoc--doc-buffer'.")
-(defun eldoc-doc-buffer ()
- "Display ElDoc documentation buffer.
+(defun eldoc-doc-buffer (&optional interactive)
+ "Get or display ElDoc documentation buffer.
-This holds the results of the last documentation request."
- (interactive)
+The buffer holds the results of the last documentation request.
+If INTERACTIVE, display it. Else, return said buffer."
+ (interactive (list t))
(unless (buffer-live-p eldoc--doc-buffer)
(user-error (format
"ElDoc buffer doesn't exist, maybe `%s' to produce one."
(substitute-command-keys "\\[eldoc]"))))
(with-current-buffer eldoc--doc-buffer
- (rename-buffer (replace-regexp-in-string "^ *" ""
- (buffer-name)))
- (display-buffer (current-buffer))))
+ (cond (interactive
+ (rename-buffer (replace-regexp-in-string "^ *" ""
+ (buffer-name)))
+ (display-buffer (current-buffer)))
+ (t (current-buffer)))))
(defun eldoc--format-doc-buffer (docs)
"Ensure DOCS are displayed in an *eldoc* buffer."
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 4aeca9c6b00..ffca0dcf4f5 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -171,6 +171,8 @@ This command assumes point is not in a string or comment.
If INTERACTIVE is non-nil, as it is interactively,
report errors as appropriate for this kind of usage."
(interactive "^p\nd")
+ (when (ppss-comment-or-string-start (syntax-ppss))
+ (user-error "This command doesn't work in strings or comments"))
(if interactive
(condition-case _
(down-list arg nil)
diff --git a/lisp/emacs-lisp/oclosure.el b/lisp/emacs-lisp/oclosure.el
index cb8c59b05a2..9775e8cc656 100644
--- a/lisp/emacs-lisp/oclosure.el
+++ b/lisp/emacs-lisp/oclosure.el
@@ -223,7 +223,7 @@ list of slot properties. The currently known properties are the following:
`:mutable': A non-nil value mean the slot can be mutated.
`:type': Specifies the type of the values expected to appear in the slot."
(declare (doc-string 2) (indent 1))
- (unless (stringp docstring)
+ (unless (or (stringp docstring) (null docstring))
(push docstring slots)
(setq docstring nil))
(let* ((options (when (consp name)
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index c699454b0bb..8f9b610ba78 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -2886,7 +2886,13 @@ either a full name or nil, and EMAIL is a valid email address."
(define-derived-mode package-menu-mode tabulated-list-mode "Package Menu"
"Major mode for browsing a list of packages.
-Letters do not insert themselves; instead, they are commands.
+The most useful commands here are:
+
+ `x': Install the package under point if it isn't already installed,
+ and delete it if it's already installed,
+ `i': mark a package for installation, and
+ `d': mark a package for deletion. Use the `x' command to perform the
+ actions on the marked files.
\\<package-menu-mode-map>
\\{package-menu-mode-map}"
:interactive nil
@@ -3633,8 +3639,13 @@ packages list, respectively."
(defun package-menu-execute (&optional noquery)
"Perform marked Package Menu actions.
Packages marked for installation are downloaded and installed,
-packages marked for deletion are removed,
-and packages marked for upgrading are downloaded and upgraded.
+packages marked for deletion are removed, and packages marked for
+upgrading are downloaded and upgraded.
+
+If no packages are marked, the action taken depends on the state
+of the package under point. If it's not already installed, this
+command will install the package, and if it's installed, it will
+delete the package.
Optional argument NOQUERY non-nil means do not ask the user to confirm."
(interactive nil package-menu-mode)
@@ -3652,8 +3663,20 @@ Optional argument NOQUERY non-nil means do not ask the user to confirm."
((eq cmd ?I)
(push pkg-desc install-list))))
(forward-line)))
+ ;; Nothing marked.
(unless (or delete-list install-list)
- (user-error "No operations specified"))
+ ;; Not on a package line.
+ (unless (tabulated-list-get-id)
+ (user-error "No operations specified"))
+ (let* ((id (tabulated-list-get-id))
+ (status (package-menu-get-status)))
+ (cond
+ ((member status '("installed"))
+ (push id delete-list))
+ ((member status '("available" "avail-obso" "new" "dependency"))
+ (push id install-list))
+ (t (user-error "No default action available for status: %s"
+ status)))))
(let-alist (package-menu--partition-transaction install-list delete-list)
(when (or noquery
(package-menu--prompt-transaction-p .delete .install .upgrade))
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index ebf3c6b1fe9..340fe766c1e 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1298,16 +1298,20 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'),
:eval (keymap-lookup (current-global-map) "C-x x g")))
;;;###autoload
-(defun shortdoc-display-group (group &optional function)
+(defun shortdoc-display-group (group &optional function same-window)
"Pop to a buffer with short documentation summary for functions in GROUP.
-If FUNCTION is non-nil, place point on the entry for FUNCTION (if any)."
+If FUNCTION is non-nil, place point on the entry for FUNCTION (if any).
+If SAME-WINDOW, don't pop to a new window."
(interactive (list (completing-read "Show summary for functions in: "
(mapcar #'car shortdoc--groups))))
(when (stringp group)
(setq group (intern group)))
(unless (assq group shortdoc--groups)
(error "No such documentation group %s" group))
- (pop-to-buffer (format "*Shortdoc %s*" group))
+ (funcall (if same-window
+ #'pop-to-buffer-same-window
+ #'pop-to-buffer)
+ (format "*Shortdoc %s*" group))
(let ((inhibit-read-only t)
(prev nil))
(erase-buffer)
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el
index 2bab1319132..61d52026b38 100644
--- a/lisp/emacs-lisp/smie.el
+++ b/lisp/emacs-lisp/smie.el
@@ -1846,7 +1846,9 @@ to which that point should be aligned, if we were to reindent it.")
(move-to-column fc)
(syntax-ppss))))
(while
- (and (with-demoted-errors "SMIE Error: %S"
+ ;; We silence the error completely since errors are "normal" in
+ ;; some cases and an error message would be annoying (bug#19342).
+ (and (ignore-error scan-error
(save-excursion
(let ((end (point))
(bsf nil) ;Best-so-far.
diff --git a/lisp/faces.el b/lisp/faces.el
index 12a386c8f63..2d4b7761be6 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -1148,13 +1148,18 @@ returned. Otherwise, DEFAULT is returned verbatim."
nil t nil 'face-name-history default))
;; Ignore elements that are not faces
;; (for example, because DEFAULT was "all faces")
- (if (facep face) (push (intern face) faces)))
+ (if (facep face) (push (if (stringp face)
+ (intern face)
+ face)
+ faces)))
(nreverse faces))
(let ((face (completing-read
prompt
(completion-table-in-turn nonaliasfaces aliasfaces)
nil t nil 'face-name-history defaults)))
- (if (facep face) (intern face)))))))
+ (when (facep face) (if (stringp face)
+ (intern face)
+ face)))))))
;; Not defined without X, but behind window-system test.
(defvar x-bitmap-file-path)
@@ -1202,8 +1207,9 @@ an integer value."
(:height
'integerp)
(:stipple
- (and (memq (window-system frame) '(x ns pgtk)) ; No stipple on w32 or haiku
- (mapcar #'list
+ (and (memq (window-system frame) '(x ns pgtk haiku)) ; No stipple on w32
+ (mapcar (lambda (item)
+ (cons item item))
(apply #'nconc
(mapcar (lambda (dir)
(and (file-readable-p dir)
diff --git a/lisp/gnus/gnus-search.el b/lisp/gnus/gnus-search.el
index 17724c3a514..369df81d9bd 100644
--- a/lisp/gnus/gnus-search.el
+++ b/lisp/gnus/gnus-search.el
@@ -1337,7 +1337,11 @@ elements are present."
(cl-defmethod gnus-search-imap-handle-string ((engine gnus-search-imap)
(str string))
(with-slots (literal-plus) engine
- (if (multibyte-string-p str)
+ ;; TODO: Figure out how Exchange IMAP servers actually work. They
+ ;; do not accept any CHARSET but US-ASCII, but they do report
+ ;; Literal+ capability. So what do we do? Will quoted strings
+ ;; always work?
+ (if (string-match-p "[^[:ascii:]]" str)
;; If LITERAL+ is available, use it and encode string as
;; UTF-8.
(if literal-plus
diff --git a/lisp/gnus/nnvirtual.el b/lisp/gnus/nnvirtual.el
index cc87a707ce6..ae4265de7fb 100644
--- a/lisp/gnus/nnvirtual.el
+++ b/lisp/gnus/nnvirtual.el
@@ -114,14 +114,9 @@ It is computed from the marks of individual component groups.")
(gnus-check-server
(gnus-find-method-for-group cgroup) t)
(gnus-request-group cgroup t)
- (setq prefix (gnus-group-real-prefix cgroup))
- ;; FIX FIX FIX we want to check the cache!
- ;; This is probably evil if people have set
- ;; gnus-use-cache to nil themselves, but I
- ;; have no way of finding the true value of it.
- (let ((gnus-use-cache t))
- (setq result (gnus-retrieve-headers
- articles cgroup nil))))
+ (setq prefix (gnus-group-real-prefix cgroup)
+ result (gnus-retrieve-headers
+ articles cgroup nil)))
(set-buffer nntp-server-buffer)
;; If we got HEAD headers, we convert them into NOV
;; headers. This is slow, inefficient and, come to think
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 0cb2c6d5d77..927a4f0d2c4 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -837,7 +837,8 @@ the C sources, too."
(insert-text-button
(symbol-name group)
'action (lambda (_)
- (shortdoc-display-group group object))
+ (shortdoc-display-group group object
+ help-window-keep-selected))
'follow-link t
'help-echo (purecopy "mouse-1, RET: show documentation group")))
groups)
diff --git a/lisp/help-mode.el b/lisp/help-mode.el
index 94bd5911311..4a65f40507b 100644
--- a/lisp/help-mode.el
+++ b/lisp/help-mode.el
@@ -415,7 +415,9 @@ Commands:
help-mode-tool-bar-map)
(setq-local help-mode--current-data nil)
(setq-local bookmark-make-record-function
- #'help-bookmark-make-record))
+ #'help-bookmark-make-record)
+ (unless search-default-mode
+ (isearch-fold-quotes-mode)))
;;;###autoload
(defun help-mode-setup ()
@@ -450,6 +452,7 @@ Commands:
"\\(symbol\\|program\\|property\\)\\|" ; Don't link
"\\(source \\(?:code \\)?\\(?:of\\|for\\)\\)\\)"
"[ \t\n]+\\)?"
+ "\\(\\\\\\+\\)?"
"['`‘]\\(\\(?:\\sw\\|\\s_\\)+\\|`\\)['’]"))
"Regexp matching doc string references to symbols.
@@ -626,27 +629,28 @@ that."
;; Quoted symbols
(save-excursion
(while (re-search-forward help-xref-symbol-regexp nil t)
- (let* ((data (match-string 8))
- (sym (intern-soft data)))
- (if sym
- (cond
- ((match-string 3) ; `variable' &c
- (and (or (boundp sym) ; `variable' doesn't ensure
+ (when-let ((sym (intern-soft (match-string 9))))
+ (if (match-string 8)
+ (delete-region (match-beginning 8)
+ (match-end 8))
+ (cond
+ ((match-string 3) ; `variable' &c
+ (and (or (boundp sym) ; `variable' doesn't ensure
; it's actually bound
- (get sym 'variable-documentation))
- (help-xref-button 8 'help-variable sym)))
- ((match-string 4) ; `function' &c
- (and (fboundp sym) ; similarly
- (help-xref-button 8 'help-function sym)))
- ((match-string 5) ; `face'
- (and (facep sym)
- (help-xref-button 8 'help-face sym)))
- ((match-string 6)) ; nothing for `symbol'
- ((match-string 7)
- (help-xref-button 8 'help-function-def sym))
- ((cl-some (lambda (x) (funcall (nth 1 x) sym))
- describe-symbol-backends)
- (help-xref-button 8 'help-symbol sym)))))))
+ (get sym 'variable-documentation))
+ (help-xref-button 9 'help-variable sym)))
+ ((match-string 4) ; `function' &c
+ (and (fboundp sym) ; similarly
+ (help-xref-button 9 'help-function sym)))
+ ((match-string 5) ; `face'
+ (and (facep sym)
+ (help-xref-button 9 'help-face sym)))
+ ((match-string 6)) ; nothing for `symbol'
+ ((match-string 7)
+ (help-xref-button 9 'help-function-def sym))
+ ((cl-some (lambda (x) (funcall (nth 1 x) sym))
+ describe-symbol-backends)
+ (help-xref-button 9 'help-symbol sym)))))))
;; An obvious case of a key substitution:
(save-excursion
(while (re-search-forward
diff --git a/lisp/icomplete.el b/lisp/icomplete.el
index 2986aa192c8..a0f105a628d 100644
--- a/lisp/icomplete.el
+++ b/lisp/icomplete.el
@@ -139,7 +139,9 @@ See `icomplete-delay-completions-threshold'."
:type 'integer)
(defvar icomplete-in-buffer nil
- "If non-nil, also use Icomplete when completing in non-mini buffers.")
+ "If non-nil, also use Icomplete when completing in non-mini buffers.
+This affects commands like `complete-in-region', but not commands
+like `dabbrev-completion', which uses its own completion setup.")
(defcustom icomplete-minibuffer-setup-hook nil
"Icomplete-specific customization of minibuffer setup.
@@ -153,8 +155,7 @@ with other features and packages. For instance:
will constrain Emacs to a maximum minibuffer height of 3 lines when
icompletion is occurring."
- :type 'hook
- :group 'icomplete)
+ :type 'hook)
;;;_* Initialization
@@ -174,11 +175,11 @@ Used to implement the option `icomplete-show-matches-on-no-input'.")
(defvar icomplete-minibuffer-map
(let ((map (make-sparse-keymap)))
- (define-key map [?\M-\t] 'icomplete-force-complete)
- (define-key map [remap minibuffer-complete-and-exit] 'icomplete-ret)
- (define-key map [?\C-j] 'icomplete-force-complete-and-exit)
- (define-key map [?\C-.] 'icomplete-forward-completions)
- (define-key map [?\C-,] 'icomplete-backward-completions)
+ (define-key map [?\M-\t] #'icomplete-force-complete)
+ (define-key map [remap minibuffer-complete-and-exit] #'icomplete-ret)
+ (define-key map [?\C-j] #'icomplete-force-complete-and-exit)
+ (define-key map [?\C-.] #'icomplete-forward-completions)
+ (define-key map [?\C-,] #'icomplete-backward-completions)
map)
"Keymap used by `icomplete-mode' in the minibuffer.")
@@ -394,18 +395,18 @@ if that doesn't produce a completion match."
(defvar icomplete-fido-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-k") 'icomplete-fido-kill)
- (define-key map (kbd "C-d") 'icomplete-fido-delete-char)
- (define-key map (kbd "RET") 'icomplete-fido-ret)
- (define-key map (kbd "C-m") 'icomplete-fido-ret)
- (define-key map (kbd "DEL") 'icomplete-fido-backward-updir)
- (define-key map (kbd "M-j") 'icomplete-fido-exit)
- (define-key map (kbd "C-s") 'icomplete-forward-completions)
- (define-key map (kbd "C-r") 'icomplete-backward-completions)
- (define-key map (kbd "<right>") 'icomplete-forward-completions)
- (define-key map (kbd "<left>") 'icomplete-backward-completions)
- (define-key map (kbd "C-.") 'icomplete-forward-completions)
- (define-key map (kbd "C-,") 'icomplete-backward-completions)
+ (define-key map (kbd "C-k") #'icomplete-fido-kill)
+ (define-key map (kbd "C-d") #'icomplete-fido-delete-char)
+ (define-key map (kbd "RET") #'icomplete-fido-ret)
+ (define-key map (kbd "C-m") #'icomplete-fido-ret)
+ (define-key map (kbd "DEL") #'icomplete-fido-backward-updir)
+ (define-key map (kbd "M-j") #'icomplete-fido-exit)
+ (define-key map (kbd "C-s") #'icomplete-forward-completions)
+ (define-key map (kbd "C-r") #'icomplete-backward-completions)
+ (define-key map (kbd "<right>") #'icomplete-forward-completions)
+ (define-key map (kbd "<left>") #'icomplete-backward-completions)
+ (define-key map (kbd "C-.") #'icomplete-forward-completions)
+ (define-key map (kbd "C-,") #'icomplete-backward-completions)
map)
"Keymap used by `fido-mode' in the minibuffer.")
@@ -431,7 +432,7 @@ if that doesn't produce a completion match."
This global minor mode makes minibuffer completion behave
more like `ido-mode' than regular `icomplete-mode'."
- :global t :group 'icomplete
+ :global t
(remove-hook 'minibuffer-setup-hook #'icomplete-minibuffer-setup)
(remove-hook 'minibuffer-setup-hook #'icomplete--fido-mode-setup)
(when fido-mode
@@ -457,7 +458,7 @@ You can use the following key bindings to navigate and select
completions:
\\{icomplete-minibuffer-map}"
- :global t :group 'icomplete
+ :global t
(remove-hook 'minibuffer-setup-hook #'icomplete-minibuffer-setup)
(remove-hook 'completion-in-region-mode-hook #'icomplete--in-region-setup)
(when icomplete-mode
@@ -532,7 +533,7 @@ Usually run by inclusion in `minibuffer-setup-hook'."
(setq icomplete--in-region-buffer nil)
(delete-overlay icomplete-overlay)
(kill-local-variable 'completion-show-inline-help)
- (remove-hook 'post-command-hook 'icomplete-post-command-hook t)
+ (remove-hook 'post-command-hook #'icomplete-post-command-hook t)
(message nil)))
(when (and completion-in-region-mode
icomplete-mode (icomplete-simple-completing-p))
@@ -543,7 +544,7 @@ Usually run by inclusion in `minibuffer-setup-hook'."
(unless (memq icomplete-minibuffer-map (cdr tem))
(setcdr tem (make-composed-keymap icomplete-minibuffer-map
(cdr tem)))))
- (add-hook 'post-command-hook 'icomplete-post-command-hook nil t)))
+ (add-hook 'post-command-hook #'icomplete-post-command-hook nil t)))
(defun icomplete--sorted-completions ()
(or completion-all-sorted-completions
@@ -630,12 +631,12 @@ Usually run by inclusion in `minibuffer-setup-hook'."
(defvar icomplete-vertical-mode-minibuffer-map
(let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-n") 'icomplete-forward-completions)
- (define-key map (kbd "C-p") 'icomplete-backward-completions)
- (define-key map (kbd "<down>") 'icomplete-forward-completions)
- (define-key map (kbd "<up>") 'icomplete-backward-completions)
- (define-key map (kbd "M-<") 'icomplete-vertical-goto-first)
- (define-key map (kbd "M->") 'icomplete-vertical-goto-last)
+ (define-key map (kbd "C-n") #'icomplete-forward-completions)
+ (define-key map (kbd "C-p") #'icomplete-backward-completions)
+ (define-key map (kbd "<down>") #'icomplete-forward-completions)
+ (define-key map (kbd "<up>") #'icomplete-backward-completions)
+ (define-key map (kbd "M-<") #'icomplete-vertical-goto-first)
+ (define-key map (kbd "M->") #'icomplete-vertical-goto-last)
map)
"Keymap used by `icomplete-vertical-mode' in the minibuffer.")
@@ -691,7 +692,7 @@ See `icomplete-mode' and `minibuffer-setup-hook'."
(icomplete-simple-completing-p)) ;Shouldn't be necessary.
(let ((saved-point (point)))
(save-excursion
- (goto-char (point-max))
+ (goto-char (icomplete--field-end))
; Insert the match-status information:
(when (and (or icomplete-show-matches-on-no-input
(not (equal (icomplete--field-string)
@@ -1043,7 +1044,7 @@ matches exist."
(push first prospects)))
(concat determ
"{"
- (mapconcat 'identity prospects icomplete-separator)
+ (mapconcat #'identity prospects icomplete-separator)
(concat (and limit (concat icomplete-separator ellipsis))
"}")))
;; Restore the base-size info, since completion-all-sorted-completions
diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index 721f2f2bbd8..ea5d7ff0f35 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -282,10 +282,17 @@ Stop if the top edge of the image is reached."
(defun image-scroll-up (&optional n)
"Scroll image in current window upward by N lines.
Stop if the bottom edge of the image is reached.
-If ARG is omitted or nil, scroll upward by a near full screen.
+
+Interactively, giving this command a numerical prefix will scroll
+up by that many lines (and down by that many lines if the number
+is negative). Without a prefix, scroll up by a full screen.
+If given a `C-u -' prefix, scroll a full page down instead.
+
+If N is omitted or nil, scroll upward by a near full screen.
A near full screen is `next-screen-context-lines' less than a full screen.
-Negative ARG means scroll downward.
-If ARG is the atom `-', scroll downward by nearly full screen.
+A negative N means scroll downward.
+
+If N is the atom `-', scroll downward by nearly full screen.
When calling from a program, supply as argument a number, nil, or `-'."
(interactive "P")
(cond ((null n)
@@ -303,10 +310,17 @@ When calling from a program, supply as argument a number, nil, or `-'."
(defun image-scroll-down (&optional n)
"Scroll image in current window downward by N lines.
Stop if the top edge of the image is reached.
-If ARG is omitted or nil, scroll downward by a near full screen.
+
+Interactively, giving this command a numerical prefix will scroll
+down by that many lines (and up by that many lines if the number
+is negative). Without a prefix, scroll down by a full screen.
+If given a `C-u -' prefix, scroll a full page up instead.
+
+If N is omitted or nil, scroll downward by a near full screen.
A near full screen is `next-screen-context-lines' less than a full screen.
-Negative ARG means scroll upward.
-If ARG is the atom `-', scroll upward by nearly full screen.
+A negative N means scroll upward.
+
+If N is the atom `-', scroll upward by nearly full screen.
When calling from a program, supply as argument a number, nil, or `-'."
(interactive "P")
(cond ((null n)
diff --git a/lisp/info.el b/lisp/info.el
index abfb77b0552..514cf7b3f47 100644
--- a/lisp/info.el
+++ b/lisp/info.el
@@ -4490,7 +4490,9 @@ Advanced commands:
(setq-local revert-buffer-function #'Info-revert-buffer-function)
(setq-local font-lock-defaults '(Info-mode-font-lock-keywords t t))
(Info-set-mode-line)
- (setq-local bookmark-make-record-function #'Info-bookmark-make-record))
+ (setq-local bookmark-make-record-function #'Info-bookmark-make-record)
+ (unless search-default-mode
+ (isearch-fold-quotes-mode)))
;; When an Info buffer is killed, make sure the associated tags buffer
;; is killed too.
diff --git a/lisp/international/fontset.el b/lisp/international/fontset.el
index 883f08905e9..7fa390a34be 100644
--- a/lisp/international/fontset.el
+++ b/lisp/international/fontset.el
@@ -232,12 +232,14 @@
(elymaic #x10FE0)
(old-uyghur #x10F70)
(brahmi #x11013 #x11045 #x11052 #x11065)
+ (kaithi #x1108D #x110B0 #x110BD)
(mahajani #x11150)
+ (sharada #x11191 #x111B3 #x111CD)
(khojki #x11200)
(khudawadi #x112B0)
(grantha #x11305)
(newa #x11400)
- (tirhuta #x11481)
+ (tirhuta #x11481 #x1148F #x114D0)
(siddham #x11580)
(modi #x11600)
(takri #x11680)
@@ -772,6 +774,9 @@
elymaic
old-uyghur
brahmi
+ kaithi
+ sharada
+ tirhuta
makasar
dives-akuru
cuneiform
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 8397bb95c6b..96168f94bd5 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -4466,6 +4466,23 @@ CASE-FOLD non-nil means the search was case-insensitive."
(isearch-search)
(isearch-update))
+
+(defvar isearch-fold-quotes-mode--state)
+(define-minor-mode isearch-fold-quotes-mode
+ "Minor mode to aid searching for \\=` characters in help modes."
+ :lighter ""
+ (if isearch-fold-quotes-mode
+ (setq-local isearch-fold-quotes-mode--state
+ (buffer-local-set-state
+ search-default-mode
+ (lambda (string &optional _lax)
+ (thread-last
+ (regexp-quote string)
+ (replace-regexp-in-string "`" "[`‘]")
+ (replace-regexp-in-string "'" "['’]")
+ (replace-regexp-in-string "\"" "[\"“â€]")))))
+ (buffer-local-restore-state isearch-fold-quotes-mode--state)))
+
(provide 'isearch)
;;; isearch.el ends here
diff --git a/lisp/language/greek.el b/lisp/language/greek.el
index 58f4fe6fc49..920cf67d871 100644
--- a/lisp/language/greek.el
+++ b/lisp/language/greek.el
@@ -79,7 +79,9 @@
(coding-priority greek-iso-8bit)
(nonascii-translation . iso-8859-7)
(input-method . "greek")
- (documentation . t)))
+ (documentation . "Support for Greek ISO-8859-7 using the greek input method.")
+ (sample-text . "Greek (ελληνικά) Γειά σας")
+ (tutorial . "TUTORIAL.el_GR")))
(provide 'greek)
diff --git a/lisp/language/indian.el b/lisp/language/indian.el
index c3d59b6f770..4b6c4744f1c 100644
--- a/lisp/language/indian.el
+++ b/lisp/language/indian.el
@@ -136,6 +136,39 @@ South Indian language Malayalam is supported in this language environment."))
The ancient Brahmi script is supported in this language environment."))
'("Indian")) ; Should we have an "Old" category?
+(set-language-info-alist
+ "Kaithi" '((charset unicode)
+ (coding-system utf-8)
+ (coding-priority utf-8)
+ (input-method . "kaithi")
+ (sample-text . "Kaithi (ð‘‚𑂶𑂟𑂲) 𑂩𑂰𑂧𑂩𑂰𑂧")
+ (documentation . "\
+Languages such as Awadhi, Bhojpuri, Magahi and Maithili
+which used the Kaithi script are supported in this language environment."))
+ '("Indian"))
+
+(set-language-info-alist
+ "Tirhuta" '((charset unicode)
+ (coding-system utf-8)
+ (coding-priority utf-8)
+ (input-method . "tirhuta")
+ (sample-text . "Tirhuta (𑒞𑒱𑒩𑒯𑒳𑒞𑒰) 𑒣𑓂𑒩𑒢𑒰𑒧")
+ (documentation . "\
+Maithili language and its script Tirhuta is supported in this
+language environment."))
+ '("Indian"))
+
+(set-language-info-alist
+ "Sharada" '((charset unicode)
+ (coding-system utf-8)
+ (coding-priority utf-8)
+ (input-method . "sharada")
+ (sample-text . "Sharada (𑆯𑆳𑆫𑆢𑆳) 𑆤𑆩𑆱𑇀𑆑𑆳𑆫")
+ (documentation . "\
+Kashmiri language and its script Sharada is supported in this
+language environment."))
+ '("Indian"))
+
;; Replace mnemonic characters in REGEXP according to TABLE. TABLE is
;; an alist of (MNEMONIC-STRING . REPLACEMENT-STRING).
@@ -158,6 +191,8 @@ The ancient Brahmi script is supported in this language environment."))
("H" . "\u094D") ; HALANT
("s" . "[\u0951\u0952]") ; stress sign
("t" . "[\u0953\u0954]") ; accent
+ ("1" . "\u0967") ; numeral 1
+ ("3" . "\u0969") ; numeral 3
("N" . "\u200C") ; ZWNJ
("J" . "\u200D") ; ZWJ
("X" . "[\u0900-\u097F]")))) ; all coverage
@@ -169,6 +204,8 @@ The ancient Brahmi script is supported in this language environment."))
"Cn?\\(?:J?HJ?Cn?\\)*\\(?:H[NJ]?\\|v*n?a?s?t?A?\\)\\|"
;; special consonant form, or
"JHR\\|"
+ ;; vedic accents with numerals, or
+ "1ss?\\|3ss\\|s3ss\\|"
;; any other singleton characters
"X")
table))
@@ -179,14 +216,15 @@ The ancient Brahmi script is supported in this language environment."))
'(("a" . "\u0981") ; SIGN CANDRABINDU
("A" . "[\u0982\u0983]") ; SIGN ANUSVARA .. VISARGA
("V" . "[\u0985-\u0994\u09E0\u09E1]") ; independent vowel
- ("C" . "[\u0995-\u09B9\u09DC-\u09DF\u09F1]") ; consonant
+ ("C" . "[\u0995-\u09B9\u09DC-\u09DF\u09F0\u09F1]") ; consonant
("B" . "[\u09AC\u09AF\u09B0\u09F0]") ; BA, YA, RA
("R" . "[\u09B0\u09F0]") ; RA
("n" . "\u09BC") ; NUKTA
("v" . "[\u09BE-\u09CC\u09D7\u09E2\u09E3]") ; vowel sign
("H" . "\u09CD") ; HALANT
("T" . "\u09CE") ; KHANDA TA
- ("N" . "\u200C") ; ZWNJ
+ ("S" . "\u09FE") ; SANDHI MARK
+ ("N" . "\u200C") ; ZWNJ
("J" . "\u200D") ; ZWJ
("X" . "[\u0980-\u09FF]")))) ; all coverage
(indian-compose-regexp
@@ -194,7 +232,7 @@ The ancient Brahmi script is supported in this language environment."))
;; syllables with an independent vowel, or
"\\(?:RH\\)?Vn?\\(?:J?HB\\)?v*n?a?A?\\|"
;; consonant-based syllables, or
- "Cn?\\(?:J?HJ?Cn?\\)*\\(?:H[NJ]?\\|v*[NJ]?v?a?A?\\)\\|"
+ "Cn?\\(?:J?HJ?Cn?\\)*\\(?:H[NJ]?\\|v*[NJ]?v?a?A?S?\\)\\|"
;; another syllables with an independent vowel, or
"\\(?:RH\\)?T\\|"
;; special consonant form, or
@@ -421,6 +459,78 @@ The ancient Brahmi script is supported in this language environment."))
(concat multiplier number-joiner numeral)
1 'font-shape-gstring))))
+;; Kaithi composition rules
+(let ((consonant "[\x1108D-\x110AF]")
+ (nukta "\x110BA")
+ (vowel "[\x1108D-\x110C2]")
+ (anusvara-candrabindu "[\x11080\x11081]")
+ (virama "\x110B9")
+ (number-sign "\x110BD")
+ (number-sign-above "\x110CD")
+ (numerals "[\x966-\x96F]+")
+ (zwj "\x200D"))
+ (set-char-table-range composition-function-table
+ '(#x110B0 . #x110BA)
+ (list (vector
+ ;; Consonant based syllables
+ (concat consonant nukta "?\\(?:" virama zwj "?" consonant nukta "?\\)*\\(?:"
+ virama zwj "?\\|" vowel "*" nukta "?" anusvara-candrabindu "?\\)")
+ 1 'font-shape-gstring)))
+ (set-char-table-range composition-function-table
+ '(#x110BD . #x110BD)
+ (list (vector
+ ;; Number sign
+ (concat number-sign numerals)
+ 0 'font-shape-gstring)))
+ (set-char-table-range composition-function-table
+ '(#x110CD . #x110CD)
+ (list (vector
+ ;; Number sign above
+ (concat number-sign-above numerals)
+ 0 'font-shape-gstring))))
+
(provide 'indian)
+;; Tirhuta composition rules
+(let ((consonant "[\x1148F-\x114AF]")
+ (nukta "\x114C3")
+ (vowel "[\x114B0-\x114BE]")
+ (anusvara-candrabindu "[\x114BF\x114C0]")
+ (virama "\x114C2"))
+ (set-char-table-range composition-function-table
+ '(#x114B0 . #x114C3)
+ (list (vector
+ ;; Consonant based syllables
+ (concat consonant nukta "?\\(?:" virama consonant nukta "?\\)*\\(?:"
+ virama "\\|" vowel "*" nukta "?" anusvara-candrabindu "?\\)")
+ 1 'font-shape-gstring))))
+
+;; Sharada composition rules
+(let ((consonant "[\x11191-\x111B2]")
+ (nukta "\x111CA")
+ (vowel "[\x111B3-\x111BF\x111CE]")
+ (vowel-modifier "\x111CB")
+ (extra-short-vowel-mark "\x111CC")
+ (anusvara-candrabindu "[\x11181\x11180\x111CF]")
+ (virama "\x111C0")
+ (fricatives "[\x111C2\x111C3]")
+ (sandhi-mark "\x111C9")
+ (misc "[^\x11180-\x111C0\x111C2\x111C3\x111C9-\x111CC\x111CE-\x111CF]"))
+ (set-char-table-range composition-function-table
+ '(#x111B3 . #x111CF)
+ (list (vector
+ ;; Consonant based syllables
+ (concat consonant nukta "?" vowel-modifier "?\\(?:" virama
+ consonant nukta "?" vowel-modifier "?\\)*\\(?:" virama
+ "\\|" vowel "*" nukta "?" anusvara-candrabindu "?"
+ extra-short-vowel-mark "?" vowel-modifier "?" sandhi-mark
+ "?+" misc "?\\)")
+ 1 'font-shape-gstring)))
+ (set-char-table-range composition-function-table
+ '(#x111C2 . #x111C3)
+ (list (vector
+ ;; Fricatives with Consonants
+ (concat fricatives "?" consonant vowel "?")
+ 0 'font-shape-gstring))))
+
;;; indian.el ends here
diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el
index a049f65e4d0..b79c6b2a08b 100644
--- a/lisp/ldefs-boot.el
+++ b/lisp/ldefs-boot.el
@@ -1130,6 +1130,9 @@ consider all symbols (if they match PATTERN).
Return list of symbols and documentation found.
+The *Apropos* window will be selected if `help-window-select' is
+non-nil.
+
\(fn PATTERN &optional DO-ALL)" t nil)
(autoload 'apropos-library "apropos" "\
@@ -7685,6 +7688,12 @@ If NODISPLAY is non-nil, don't redisplay the article buffer.
\(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode) nil)
+(autoload 'gnus-article-outlook-rearrange-citation "deuglify" "\
+Repair broken citations.
+If NODISPLAY is non-nil, don't redisplay the article buffer.
+
+\(fn &optional NODISPLAY)" '(gnus-article-mode gnus-summary-mode) nil)
+
(autoload 'gnus-outlook-deuglify-article "deuglify" "\
Full deuglify of broken Outlook (Express) articles.
Treat \"smartquotes\", unwrap lines, repair attribution and
@@ -7696,7 +7705,7 @@ article buffer.
(autoload 'gnus-article-outlook-deuglify-article "deuglify" "\
Deuglify broken Outlook (Express) articles and redisplay." '(gnus-article-mode gnus-summary-mode) nil)
-(register-definition-prefixes "deuglify" '("gnus-"))
+(register-definition-prefixes "deuglify" '("gnus-outlook-"))
;;;***
@@ -9230,6 +9239,11 @@ If regular expression is nil, repeat last search.
Query replace FROM with TO in all files of a class tree.
With prefix arg, process files of marked classes only.
+As each match is found, the user must type a character saying
+what to do with it. Type SPC or `y' to replace the match,
+DEL or `n' to skip and go to the next match. For more directions,
+type \\[help-command] at that time.
+
\(fn FROM TO)" t nil)
(autoload 'ebrowse-tags-search-member-use "ebrowse" "\
@@ -11613,7 +11627,13 @@ Do `query-replace-regexp' of FROM with TO on all files listed in tags table.
Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
with the command \\[fileloop-continue].
-For non-interactive use, superseded by `fileloop-initialize-replace'.
+
+As each match is found, the user must type a character saying
+what to do with it. Type SPC or `y' to replace the match,
+DEL or `n' to skip and go to the next match. For more directions,
+type \\[help-command] at that time.
+
+For non-interactive use, this is superseded by `fileloop-initialize-replace'.
\(fn FROM TO &optional DELIMITED FILES)" t nil)
@@ -13947,7 +13967,7 @@ and choose the directory as the fortune-file.
Minimum set of parameters to filter for live (on-session) framesets.
DO NOT MODIFY. See `frameset-filter-alist' for a full description.")
-(defvar frameset-persistent-filter-alist (append '((background-color . frameset-filter-sanitize-color) (buffer-list . :never) (buffer-predicate . :never) (buried-buffer-list . :never) (client . :never) (delete-before . :never) (font . frameset-filter-font-param) (font-backend . :never) (foreground-color . frameset-filter-sanitize-color) (frameset--text-pixel-height . :save) (frameset--text-pixel-width . :save) (fullscreen . frameset-filter-shelve-param) (GUI:font . frameset-filter-unshelve-param) (GUI:fullscreen . frameset-filter-unshelve-param) (GUI:height . frameset-filter-unshelve-param) (GUI:width . frameset-filter-unshelve-param) (height . frameset-filter-shelve-param) (parent-frame . :never) (mouse-wheel-frame . :never) (tty . frameset-filter-tty-to-GUI) (tty-type . frameset-filter-tty-to-GUI) (width . frameset-filter-shelve-param) (window-system . :never)) frameset-session-filter-alist) "\
+(defvar frameset-persistent-filter-alist (append '((background-color . frameset-filter-sanitize-color) (bottom . frameset-filter-shelve-param) (buffer-list . :never) (buffer-predicate . :never) (buried-buffer-list . :never) (client . :never) (delete-before . :never) (font . frameset-filter-font-param) (font-backend . :never) (foreground-color . frameset-filter-sanitize-color) (frameset--text-pixel-height . :save) (frameset--text-pixel-width . :save) (fullscreen . frameset-filter-shelve-param) (GUI:bottom . frameset-filter-unshelve-param) (GUI:font . frameset-filter-unshelve-param) (GUI:fullscreen . frameset-filter-unshelve-param) (GUI:height . frameset-filter-unshelve-param) (GUI:left . frameset-filter-unshelve-param) (GUI:right . frameset-filter-unshelve-param) (GUI:top . frameset-filter-unshelve-param) (GUI:width . frameset-filter-unshelve-param) (height . frameset-filter-shelve-param) (left . frameset-filter-shelve-param) (parent-frame . :never) (mouse-wheel-frame . :never) (right . frameset-filter-shelve-param) (top . frameset-filter-shelve-param) (tty . frameset-filter-tty-to-GUI) (tty-type . frameset-filter-tty-to-GUI) (width . frameset-filter-shelve-param) (window-system . :never)) frameset-session-filter-alist) "\
Parameters to filter for persistent framesets.
DO NOT MODIFY. See `frameset-filter-alist' for a full description.")
@@ -19265,7 +19285,10 @@ mode doesn't have any Info manuals known to Emacs, the command will
prompt for MODE to use, with completion. With prefix arg, the command
always prompts for MODE.
-\(fn SYMBOL &optional MODE)" t nil)
+Is SAME-WINDOW, try to reuse the current window instead of
+popping up a new one.
+
+\(fn SYMBOL &optional MODE SAME-WINDOW)" t nil)
(put 'info-lookup-file 'info-file "emacs")
(autoload 'info-lookup-file "info-look" "\
@@ -20463,6 +20486,10 @@ sleep in seconds.
(autoload 'linum-mode "linum" "\
Toggle display of line numbers in the left margin (Linum mode).
+This mode has been largely replaced by `display-line-numbers-mode'
+\(which is much faster and has fewer interaction problems with other
+modes).
+
Linum mode is a buffer-local minor mode.
This is a minor mode. If called interactively, toggle the `Linum
@@ -24325,7 +24352,7 @@ Coloring:
;;;### (autoloads nil "org" "org/org.el" (0 0 0 0))
;;; Generated autoloads from org/org.el
-(push (purecopy '(org 9 5 2)) package--builtin-versions)
+(push (purecopy '(org 9 5 3)) package--builtin-versions)
(autoload 'org-babel-do-load-languages "org" "\
Load the languages defined in `org-babel-load-languages'.
@@ -25238,6 +25265,11 @@ to install it but still mark it as selected.
\(fn PKG &optional DONT-SELECT)" t nil)
+(autoload 'package-update "package" "\
+Update package NAME if a newer version exists.
+
+\(fn NAME)" t nil)
+
(autoload 'package-install-from-buffer "package" "\
Install a package from the current buffer.
The current buffer is assumed to be a single .el or .tar file or
@@ -26984,6 +27016,10 @@ command \\[fileloop-continue].
(autoload 'project-query-replace-regexp "project" "\
Query-replace REGEXP in all the files of the project.
Stops when a match is found and prompts for whether to replace it.
+At that prompt, the user must type a character saying what to do
+with the match. Type SPC or `y' to replace the match,
+DEL or `n' to skip and go to the next match. For more directions,
+type \\[help-command] at that time.
If you exit the `query-replace', you can later continue the
`query-replace' loop using the command \\[fileloop-continue].
@@ -32955,38 +32991,6 @@ Studlify-case the current buffer." t nil)
;;;### (autoloads nil "subr-x" "emacs-lisp/subr-x.el" (0 0 0 0))
;;; Generated autoloads from emacs-lisp/subr-x.el
-(autoload 'if-let "subr-x" "\
-Bind variables according to SPEC and evaluate THEN or ELSE.
-Evaluate each binding in turn, as in `let*', stopping if a
-binding value is nil. If all are non-nil return the value of
-THEN, otherwise the last form in ELSE.
-
-Each element of SPEC is a list (SYMBOL VALUEFORM) that binds
-SYMBOL to the value of VALUEFORM. An element can additionally be
-of the form (VALUEFORM), which is evaluated and checked for nil;
-i.e. SYMBOL can be omitted if only the test result is of
-interest. It can also be of the form SYMBOL, then the binding of
-SYMBOL is checked for nil.
-
-As a special case, interprets a SPEC of the form (SYMBOL SOMETHING)
-like ((SYMBOL SOMETHING)). This exists for backward compatibility
-with an old syntax that accepted only one binding.
-
-\(fn SPEC THEN &rest ELSE)" nil t)
-
-(function-put 'if-let 'lisp-indent-function '2)
-
-(autoload 'when-let "subr-x" "\
-Bind variables according to SPEC and conditionally evaluate BODY.
-Evaluate each binding in turn, stopping if a binding value is nil.
-If all are non-nil, return the value of the last form in BODY.
-
-The variable list SPEC is the same as in `if-let'.
-
-\(fn SPEC &rest BODY)" nil t)
-
-(function-put 'when-let 'lisp-indent-function '1)
-
(autoload 'string-truncate-left "subr-x" "\
Truncate STRING to LENGTH, replacing initial surplus with \"...\".
@@ -33026,7 +33030,7 @@ Query the user for a process and return the process object.
\(fn PROMPT)" nil nil)
-(register-definition-prefixes "subr-x" '("and-let*" "hash-table-" "if-let*" "internal--" "named-let" "replace-region-contents" "string-" "thread-" "when-let*" "with-memoization"))
+(register-definition-prefixes "subr-x" '("hash-table-" "internal--thread-argument" "named-let" "replace-region-contents" "string-" "thread-" "with-"))
;;;***
diff --git a/lisp/leim/quail/indian.el b/lisp/leim/quail/indian.el
index f2d5f9bad4a..b1e547a26ec 100644
--- a/lisp/leim/quail/indian.el
+++ b/lisp/leim/quail/indian.el
@@ -835,5 +835,332 @@ Full key sequences are listed below:")
("`/" ?ð‘¿)
)
+(quail-define-package
+ "kaithi" "Kaithi" "ð‘‚𑂶" t "Kaithi phonetic input method.
+
+ `\\=`' is used to switch levels instead of Alt-Gr.
+" nil t t t t nil nil nil nil nil t)
+
+(quail-define-rules
+("``" ?₹)
+("1" ?१)
+("`1" ?1)
+("2" ?२)
+("`2" ?2)
+("3" ?३)
+("`3" ?3)
+("4" ?४)
+("`4" ?4)
+("5" ?५)
+("`5" ?5)
+("6" ?६)
+("`6" ?6)
+("7" ?७)
+("`7" ?7)
+("8" ?८)
+("`8" ?8)
+("9" ?९)
+("`9" ?9)
+("0" ?०)
+("`0" ?0)
+("`\)" ?ð‘‚»)
+("`\\" ?𑃀)
+("`|" ?ð‘ƒ)
+("`" ?ð‘‚—)
+("q" ?ð‘‚—)
+("Q" ?𑂘)
+("w" ?ð‘‚™)
+("W" ?ð‘‚›)
+("`w" ?ð‘‚š)
+("`W" ?𑂜)
+("e" ?ð‘‚µ)
+("E" ?𑂶)
+("`e" ?𑂉)
+("`E" ?ð‘‚Š)
+("r" ?ð‘‚©)
+("R" ?𑃂)
+("t" ?ð‘‚ž)
+("T" ?ð‘‚Ÿ)
+("y" ?𑂨)
+("Y" ?⸱)
+("u" ?ð‘‚³)
+("U" ?ð‘‚´)
+("`u" ?𑂇)
+("`U" ?𑂈)
+("i" ?ð‘‚±)
+("I" ?ð‘‚²)
+("`i" ?ð‘‚…)
+("`I" ?𑂆)
+("o" ?ð‘‚·)
+("O" ?𑂸)
+("`o" ?ð‘‚‹)
+("`O" ?𑂌)
+("p" ?ð‘‚£)
+("P" ?𑂤)
+("a" ?ð‘‚°)
+("A" ?ð‘‚„)
+("`a" ?𑂃)
+("s" ?ð‘‚®)
+("S" ?𑂬)
+("d" ?ð‘‚ )
+("D" ?ð‘‚¡)
+("`d" ?ð‘‚¼)
+("`D" #x110BD) ; Kaithi Number Sign
+("f" ?ð‘‚¹)
+("F" #x110CD) ; Kaithi Number Sign Above
+("`f" ?ð‘‚¾)
+("`F" ?ð‘‚¿)
+("g" ?ð‘‚)
+("G" ?ð‘‚)
+("h" ?𑂯)
+("H" ?ð‘‚‚)
+("j" ?ð‘‚”)
+("J" ?ð‘‚•)
+("k" ?ð‘‚)
+("K" ?ð‘‚Ž)
+("l" ?𑂪)
+("z" ?ð‘‚–)
+("Z" ?ð‘‚‘)
+("x" ?ð‘‚­)
+("X" ?𑂺)
+("c" ?ð‘‚’)
+("C" ?ð‘‚“)
+("`c" #x200C) ; ZWNJ
+("`C" #x200D) ; ZWJ
+("v" ?ð‘‚«)
+("b" ?ð‘‚¥)
+("B" ?𑂦)
+("n" ?ð‘‚¢)
+("N" ?ð‘‚)
+("m" ?𑂧)
+("M" ?ð‘‚)
+("`m" ?ð‘‚€)
+)
+
+(quail-define-package
+ "tirhuta" "Tirhuta" "ð‘’žð‘’±" t "Tirhuta phonetic input method.
+
+ `\\=`' is used to switch levels instead of Alt-Gr.
+" nil t t t t nil nil nil nil nil t)
+
+(quail-define-rules
+("``" ?₹)
+("1" ?ð‘“‘)
+("`1" ?1)
+("2" ?ð‘“’)
+("`2" ?2)
+("3" ?ð‘““)
+("`3" ?3)
+("4" ?ð‘“”)
+("`4" ?4)
+("5" ?ð‘“•)
+("`5" ?5)
+("6" ?ð‘“–)
+("`6" ?6)
+("7" ?ð‘“—)
+("`7" ?7)
+("8" ?𑓘)
+("`8" ?8)
+("9" ?ð‘“™)
+("`9" ?9)
+("0" ?ð‘“)
+("`0" ?0)
+("`\)" ?𑓆)
+("`\\" ?।)
+("`|" ?॥)
+("`" ?ð‘’™)
+("q" ?ð‘’™)
+("Q" ?ð‘’š)
+("w" ?ð‘’›)
+("W" ?𑒜)
+("e" ?ð‘’º)
+("E" ?ð‘’¹)
+("`e" ?ð‘’‹)
+("r" ?ð‘’©)
+("R" ?ð‘’µ)
+("`r" ?ð‘’‡)
+("t" ?ð‘’ž)
+("T" ?ð‘’Ÿ)
+("y" ?ð‘’¨)
+("Y" ?ð‘’»)
+("`y" ?𑒌)
+("u" ?ð‘’³)
+("U" ?ð‘’´)
+("`u" ?ð‘’…)
+("`U" ?ð‘’†)
+("i" ?ð‘’±)
+("I" ?ð‘’²)
+("`i" ?ð‘’ƒ)
+("`I" ?ð‘’„)
+("o" ?ð‘’½)
+("O" ?ð‘’¼)
+("`o" ?ð‘’)
+("p" ?ð‘’£)
+("P" ?ð‘’¤)
+("a" ?ð‘’°)
+("A" ?ð‘’‚)
+("`a" ?ð‘’)
+("s" ?ð‘’®)
+("S" ?ð‘’¬)
+("d" ?ð‘’ )
+("D" ?ð‘’¡)
+("f" ?ð‘“‚)
+("F" ?ð‘’¶)
+("`f" ?ð‘’ˆ)
+("g" ?ð‘’‘)
+("G" ?ð‘’’)
+("h" ?ð‘’¯)
+("H" ?ð‘“)
+("j" ?ð‘’–)
+("J" ?ð‘’—)
+("k" ?ð‘’)
+("K" ?ð‘’)
+("l" ?ð‘’ª)
+("L" ?ð‘’·)
+("`l" ?ð‘’‰)
+("z" ?ð‘’˜)
+("Z" ?ð‘’“)
+("`z" ?ð‘’¸)
+("`Z" ?ð‘’Š)
+("x" ?ð‘’­)
+("X" ?𑓃)
+("c" ?ð‘’”)
+("C" ?ð‘’•)
+("`c" #x200C) ; ZWNJ
+("v" ?ð‘’«)
+("V" ?ð‘’¾)
+("`v" ?ð‘’Ž)
+("b" ?ð‘’¥)
+("B" ?ð‘’¦)
+("`b" ?ð‘’€)
+("`B" ?ð‘“„)
+("n" ?ð‘’¢)
+("N" ?ð‘’)
+("`n" ?𑓇)
+("`N" ?ð‘“…)
+("m" ?ð‘’§)
+("M" ?ð‘“€)
+("`m" ?ð‘’¿)
+)
+
+(quail-define-package
+ "sharada" "Sharada" "𑆯𑆳" t "Sharada phonetic input method.
+
+ `\\=`' is used to switch levels instead of Alt-Gr.
+" nil t t t t nil nil nil nil nil t)
+
+(quail-define-rules
+("``" ?₹)
+("1" ?𑇑)
+("`1" ?1)
+("2" ?𑇒)
+("`2" ?2)
+("3" ?𑇓)
+("`3" ?3)
+("4" ?𑇔)
+("`4" ?4)
+("5" ?𑇕)
+("`5" ?5)
+("6" ?𑇖)
+("`6" ?6)
+("7" ?𑇗)
+("`7" ?7)
+("8" ?𑇘)
+("`8" ?8)
+("9" ?𑇙)
+("`9" ?9)
+("0" ?ð‘‡)
+("`0" ?0)
+("`\)" ?𑇇)
+("`\\" ?𑇅)
+("`|" ?𑇆)
+("`" ?𑆛)
+("q" ?𑆛)
+("Q" ?𑆜)
+("`q" ?𑇈)
+("`Q" ?𑇉)
+("w" ?ð‘†)
+("W" ?𑆞)
+("`w" ?𑇋)
+("`W" ?ð‘‡)
+("e" ?𑆼)
+("E" ?𑆽)
+("`e" ?ð‘†)
+("`E" ?𑆎)
+("r" ?𑆫)
+("R" ?𑆸)
+("`r" ?𑆉)
+("`R" ?𑇎)
+("t" ?𑆠)
+("T" ?𑆡)
+("y" ?𑆪)
+("u" ?𑆶)
+("U" ?𑆷)
+("`u" ?𑆇)
+("`U" ?𑆈)
+("i" ?𑆴)
+("I" ?𑆵)
+("`i" ?𑆅)
+("`I" ?𑆆)
+("o" ?𑆾)
+("O" ?𑆿)
+("`o" ?ð‘†)
+("`O" ?ð‘†)
+("p" ?𑆥)
+("P" ?𑆦)
+("`p" ?𑇃)
+("a" ?𑆳)
+("A" ?𑆄)
+("`a" ?𑆃)
+("s" ?𑆱)
+("S" ?𑆯)
+("d" ?𑆢)
+("D" ?𑆣)
+("`d" ?𑇚)
+("`D" ?𑇛)
+("f" ?𑇀)
+("F" ?𑆹)
+("`f" ?𑆊)
+("`F" ?𑇌)
+("g" ?𑆓)
+("G" ?𑆔)
+("`g" ?𑇜)
+("`G" ?ð‘‡)
+("h" ?𑆲)
+("H" ?𑆂)
+("`h" ?𑇞)
+("`H" ?𑇟)
+("j" ?𑆘)
+("J" ?𑆙)
+("`j" ?᳘)
+("`J" ?᳕)
+("k" ?𑆑)
+("K" ?𑆒)
+("`k" ?𑇂)
+("l" ?𑆬)
+("L" ?𑆭)
+("`l" ?𑆺)
+("`L" ?𑆋)
+("z" ?𑆚)
+("Z" ?𑆕)
+("`z" ?𑆻)
+("`Z" ?𑆌)
+("x" ?𑆰)
+("X" ?𑇊)
+("c" ?𑆖)
+("C" ?𑆗)
+("`c" #x200C) ; ZWNJ
+("v" ?𑆮)
+("b" ?𑆧)
+("B" ?𑆨)
+("n" ?𑆤)
+("N" ?𑆟)
+("`n" ?𑇄)
+("`N" ?ð‘‡)
+("m" ?𑆩)
+("M" ?ð‘†)
+("`m" ?𑆀)
+("`M" ?ð‘‡)
+)
;;; indian.el ends here
diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el
index 66898d77073..c563a27ac85 100644
--- a/lisp/net/browse-url.el
+++ b/lisp/net/browse-url.el
@@ -1019,6 +1019,8 @@ instead of `browse-url-new-window-flag'."
'browse-url-default-windows-browser)
((memq system-type '(darwin))
'browse-url-default-macosx-browser)
+ ((featurep 'haiku)
+ 'browse-url-default-haiku-browser)
((browse-url-can-use-xdg-open) 'browse-url-xdg-open)
;;; ((executable-find browse-url-gnome-moz-program) 'browse-url-gnome-moz)
((executable-find browse-url-mozilla-program) 'browse-url-mozilla)
@@ -1239,6 +1241,24 @@ The optional argument NEW-WINDOW is not used."
(function-put 'browse-url-webpositive 'browse-url-browser-kind 'external)
+(declare-function haiku-roster-launch "haikuselect.c")
+
+;;;###autoload
+(defun browse-url-default-haiku-browser (url &optional _new-window)
+ "Browse URL with the system default browser.
+Default to the URL around or before point."
+ (interactive (browse-url-interactive-arg "URL: "))
+ (setq url (browse-url-encode-url url))
+ (let* ((scheme (save-match-data
+ (if (string-match "\\(.+\\):/" url)
+ (match-string 1 url)
+ "http")))
+ (mime (concat "application/x-vnd.Be.URL." scheme)))
+ (haiku-roster-launch mime (vector url))))
+
+(function-put 'browse-url-default-haiku-browser
+ 'browse-url-browser-kind 'external)
+
;;;###autoload
(defun browse-url-emacs (url &optional same-window)
"Ask Emacs to load URL into a buffer and show it in another window.
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index ba4cdb0ab52..74155d1722e 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -137,6 +137,15 @@ be auto-detected by Tramp.
The string is used in `tramp-methods'.")
+(defvar tramp-scp-force-scp-protocol nil
+ "Force scp protocol.
+
+It is the string \"-O\" if supported by the local scp (since
+release 8.6), otherwise the string \"\". If it is nil, it will
+be auto-detected by Tramp.
+
+The string is used in `tramp-methods'.")
+
(defcustom tramp-use-scp-direct-remote-copying nil
"Whether to use direct copying between two remote hosts."
:group 'tramp
@@ -179,7 +188,8 @@ The string is used in `tramp-methods'.")
(tramp-remote-shell-args ("-c"))
(tramp-copy-program "scp")
(tramp-copy-args (("-P" "%p") ("-p" "%k")
- ("%x") ("%y") ("-q") ("-r") ("%c")))
+ ("%x") ("%y") ("%z")
+ ("-q") ("-r") ("%c")))
(tramp-copy-keep-date t)
(tramp-copy-recursive t)))
(add-to-list 'tramp-methods
@@ -195,7 +205,8 @@ The string is used in `tramp-methods'.")
(tramp-remote-shell-args ("-c"))
(tramp-copy-program "scp")
(tramp-copy-args (("-P" "%p") ("-p" "%k")
- ("%x") ("%y") ("-q") ("-r") ("%c")))
+ ("%x") ("%y") ("%z")
+ ("-q") ("-r") ("%c")))
(tramp-copy-keep-date t)
(tramp-copy-recursive t)))
(add-to-list 'tramp-methods
@@ -2347,7 +2358,8 @@ The method used must be an out-of-band method."
?r listener ?c options ?k (if keep-date " " "")
?n (concat "2>" (tramp-get-remote-null-device v))
?x (tramp-scp-strict-file-name-checking v)
- ?y (tramp-scp-direct-remote-copying v1 v2))
+ ?y (tramp-scp-force-scp-protocol v)
+ ?z (tramp-scp-direct-remote-copying v1 v2))
copy-program (tramp-get-method-parameter v 'tramp-copy-program)
copy-keep-date (tramp-get-method-parameter
v 'tramp-copy-keep-date)
@@ -4810,14 +4822,41 @@ Goes through the list `tramp-inline-compress-commands'."
(setq tramp-scp-strict-file-name-checking "-T")))))))
tramp-scp-strict-file-name-checking)))
+(defun tramp-scp-force-scp-protocol (vec)
+ "Return the force scp protocol argument of the local scp."
+ (cond
+ ;; No options to be computed.
+ ((null (assoc "%y" (tramp-get-method-parameter vec 'tramp-copy-args)))
+ "")
+
+ ;; There is already a value to be used.
+ ((stringp tramp-scp-force-scp-protocol)
+ tramp-scp-force-scp-protocol)
+
+ ;; Determine the options.
+ (t (setq tramp-scp-force-scp-protocol "")
+ (let ((case-fold-search t))
+ (ignore-errors
+ (when (executable-find "scp")
+ (with-tramp-progress-reporter
+ vec 4 "Computing force scp protocol argument"
+ (with-temp-buffer
+ (tramp-call-process vec "scp" nil t nil "-O")
+ (goto-char (point-min))
+ (unless
+ (search-forward-regexp
+ "\\(illegal\\|unknown\\) option -- O" nil t)
+ (setq tramp-scp-force-scp-protocol "-O")))))))
+ tramp-scp-force-scp-protocol)))
+
(defun tramp-scp-direct-remote-copying (vec1 vec2)
"Return the direct remote copying argument of the local scp."
(cond
((or (not tramp-use-scp-direct-remote-copying) (null vec1) (null vec2)
(not (tramp-get-process vec1))
(not (equal (tramp-file-name-port vec1) (tramp-file-name-port vec2)))
- (null (assoc "%y" (tramp-get-method-parameter vec1 'tramp-copy-args)))
- (null (assoc "%y" (tramp-get-method-parameter vec2 'tramp-copy-args))))
+ (null (assoc "%z" (tramp-get-method-parameter vec1 'tramp-copy-args)))
+ (null (assoc "%z" (tramp-get-method-parameter vec2 'tramp-copy-args))))
"")
((let ((case-fold-search t))
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index 968c1daccbf..8037c89829f 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -609,7 +609,11 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(if (tramp-tramp-file-p filename) filename newname))
'file-missing filename))
- (if-let ((tmpfile (file-local-copy filename)))
+ ;; `file-local-copy' returns a file name also for a local file
+ ;; with `jka-compr-handler', so we cannot trust its result as
+ ;; indication for a remote file name.
+ (if-let ((tmpfile
+ (and (file-remote-p filename) (file-local-copy filename))))
;; Remote filename.
(condition-case err
(rename-file tmpfile newname ok-if-already-exists)
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index b889f1f8848..9413f7954f4 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -255,7 +255,9 @@ pair of the form (KEY VALUE). The following KEYs are defined:
- \"%n\" expands to \"2>/dev/null\".
- \"%x\" is replaced by the `tramp-scp-strict-file-name-checking'
argument if it is supported.
- - \"%y\" is replaced by the `tramp-scp-direct-remote-copying'
+ - \"%y\" is replaced by the `tramp-scp-force-scp-protocol'
+ argument if it is supported.
+ - \"%z\" is replaced by the `tramp-scp-direct-remote-copying'
argument if it is supported.
The existence of `tramp-login-args', combined with the
@@ -3377,83 +3379,81 @@ BODY is the backend specific code."
"Skeleton for `tramp-*-handle-write-region'.
BODY is the backend specific code."
(declare (indent 7) (debug t))
- `(with-parsed-tramp-file-name (expand-file-name ,filename) nil
- (setq ,filename (expand-file-name ,filename)
- ,lockname (file-truename (or ,lockname ,filename)))
- ;; Sometimes, there is another file name handler responsible for
- ;; VISIT, for example `jka-compr-handler'. We must respect this.
- ;; See Bug#55166.
- (let ((handler (and (stringp ,visit)
- (let ((inhibit-file-name-handlers
- (cons 'tramp-file-name-handler
- inhibit-file-name-handlers))
- (inhibit-file-name-operation 'write-region))
- (find-file-name-handler ,visit 'write-region)))))
+ ;; Sometimes, there is another file name handler responsible for
+ ;; VISIT, for example `jka-compr-handler'. We must respect this.
+ ;; See Bug#55166.
+ `(let* ((filename (expand-file-name ,filename))
+ (lockname (file-truename (or ,lockname filename)))
+ (handler (and (stringp ,visit)
+ (let ((inhibit-file-name-handlers
+ `(tramp-file-name-handler
+ tramp-crypt-file-name-handler
+ . inhibit-file-name-handlers))
+ (inhibit-file-name-operation 'write-region))
+ (find-file-name-handler ,visit 'write-region)))))
+ (with-parsed-tramp-file-name filename nil
(if handler
(progn
(tramp-message
v 5 "Calling handler `%s' for visiting `%s'" handler ,visit)
(funcall
handler 'write-region
- ,start ,end ,filename ,append ,visit ,lockname ,mustbenew))
+ ,start ,end filename ,append ,visit lockname ,mustbenew))
- (when (and ,mustbenew (file-exists-p ,filename)
+ (when (and ,mustbenew (file-exists-p filename)
(or (eq ,mustbenew 'excl)
(not
(y-or-n-p
(format
- "File %s exists; overwrite anyway?" ,filename)))))
- (tramp-error v 'file-already-exists ,filename))
+ "File %s exists; overwrite anyway?" filename)))))
+ (tramp-error v 'file-already-exists filename))
- (let ((file-locked (eq (file-locked-p ,lockname) t))
+ (let ((file-locked (eq (file-locked-p lockname) t))
(uid (or (file-attribute-user-id
- (file-attributes ,filename 'integer))
+ (file-attributes filename 'integer))
(tramp-get-remote-uid v 'integer)))
(gid (or (file-attribute-group-id
- (file-attributes ,filename 'integer))
+ (file-attributes filename 'integer))
(tramp-get-remote-gid v 'integer)))
(curbuf (current-buffer)))
;; Lock file.
(when (and (not (auto-save-file-name-p
- (file-name-nondirectory ,filename)))
- (file-remote-p ,lockname)
+ (file-name-nondirectory filename)))
+ (file-remote-p lockname)
(not file-locked))
(setq file-locked t)
;; `lock-file' exists since Emacs 28.1.
- (tramp-compat-funcall 'lock-file ,lockname))
+ (tramp-compat-funcall 'lock-file lockname))
;; The body.
,@body
+ ;; We must also flush the cache of the directory, because
+ ;; `file-attributes' reads the values from there.
+ (tramp-flush-file-properties v localname)
+
;; We must protect `last-coding-system-used', now we have
;; set it to its correct value.
- (let (last-coding-system-used (need-chown t))
+ (let (last-coding-system-used)
;; Set file modification time.
(when (or (eq ,visit t) (stringp ,visit))
- (let ((file-attr (file-attributes ,filename 'integer)))
+ (when-let ((file-attr (file-attributes filename 'integer)))
(set-visited-file-modtime
;; We must pass modtime explicitly, because FILENAME
;; can be different from (buffer-file-name), f.e. if
;; `file-precious-flag' is set.
(or (file-attribute-modification-time file-attr)
(current-time)))
- (when (and (= (file-attribute-user-id file-attr) uid)
- (= (file-attribute-group-id file-attr) gid))
- (setq need-chown nil))))
-
- ;; Set the ownership.
- (when need-chown
- (tramp-set-file-uid-gid ,filename uid gid)))
-
- ;; We must also flush the cache of the directory, because
- ;; `file-attributes' reads the values from there.
- (tramp-flush-file-properties v localname)
+ ;; Set the ownership.
+ (unless (and (= (file-attribute-user-id file-attr) uid)
+ (= (file-attribute-group-id file-attr) gid))
+ (tramp-set-file-uid-gid filename uid gid)))))
;; Unlock file.
(when file-locked
;; `unlock-file' exists since Emacs 28.1.
- (tramp-compat-funcall 'unlock-file ,lockname))
+ (tramp-compat-funcall 'unlock-file lockname))
;; Sanity check.
(unless (equal curbuf (current-buffer))
@@ -3463,7 +3463,7 @@ BODY is the backend specific code."
(when (and (null noninteractive)
(or (eq ,visit t) (string-or-null-p ,visit)))
- (tramp-message v 0 "Wrote %s" ,filename))
+ (tramp-message v 0 "Wrote %s" filename))
(run-hooks 'tramp-handle-write-region-hook))))))
(put #'tramp-skeleton-write-region 'tramp-suppress-trace t)
@@ -4222,7 +4222,9 @@ Parsing the remote \"ps\" output is controlled by
It is not guaranteed, that all process attributes as described in
`process-attributes' are returned. The additional attribute
`pid' shall be returned always."
- (with-tramp-file-property vec "/" "process-attributes"
+ ;; Since Emacs 27.1.
+ (when (fboundp 'connection-local-criteria-for-default-directory)
+ (with-tramp-file-property vec "/" "process-attributes"
(ignore-errors
(with-temp-buffer
(hack-connection-local-variables-apply
@@ -4266,7 +4268,7 @@ It is not guaranteed, that all process attributes as described in
(push (append res) result))
(forward-line))
;; Return result.
- result))))))
+ result)))))))
(defun tramp-handle-list-system-processes ()
"Like `list-system-processes' for Tramp files."
@@ -4366,7 +4368,7 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.")
(make-symbolic-link info lockname 'ok-if-already-exists)
(error
(with-file-modes #o0644
- (write-region info nil lockname)))))))))
+ (write-region info nil lockname nil 'no-message)))))))))
(defun tramp-handle-make-lock-file-name (file)
"Like `make-lock-file-name' for Tramp files."
diff --git a/lisp/outline.el b/lisp/outline.el
index 7fd43195cc0..81e312ee019 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -215,6 +215,10 @@ This option is only in effect when `outline-minor-mode-cycle' is non-nil."
(let ((map (make-sparse-keymap)))
(outline-minor-mode-cycle--bind map (kbd "TAB") #'outline-cycle)
(outline-minor-mode-cycle--bind map (kbd "<backtab>") #'outline-cycle-buffer)
+ (outline-minor-mode-cycle--bind map (kbd "M-<left>") #'outline-promote)
+ (outline-minor-mode-cycle--bind map (kbd "M-<right>") #'outline-demote)
+ (outline-minor-mode-cycle--bind map (kbd "M-<up>") #'outline-move-subtree-up)
+ (outline-minor-mode-cycle--bind map (kbd "M-<down>") #'outline-move-subtree-down)
map)
"Keymap used by `outline-minor-mode-cycle'.")
diff --git a/lisp/pixel-scroll.el b/lisp/pixel-scroll.el
index b0fe2f56c03..fc7e680c262 100644
--- a/lisp/pixel-scroll.el
+++ b/lisp/pixel-scroll.el
@@ -547,7 +547,7 @@ the height of the current window."
(beginning-of-visual-line)
(point)))
t)
- (set-window-vscroll nil desired-vscroll t)))
+ (set-window-vscroll nil desired-vscroll t t)))
(defun pixel-scroll-precision-scroll-down (delta)
"Scroll the current window down by DELTA pixels."
@@ -586,7 +586,7 @@ the height of the current window."
(goto-char up-point)))
(let ((current-vscroll (window-vscroll nil t)))
(setq delta (- delta current-vscroll))
- (set-window-vscroll nil 0 t)
+ (set-window-vscroll nil 0 t t)
(when (> delta 0)
(let* ((start (window-start))
(dims (window-text-pixel-size nil (cons start (- delta))
@@ -602,7 +602,7 @@ the height of the current window."
(signal 'beginning-of-buffer nil))
(setq delta (- delta height))))
(when (< delta 0)
- (set-window-vscroll nil (- delta) t)))))
+ (set-window-vscroll nil (- delta) t t)))))
(defun pixel-scroll-precision-interpolate (delta &optional old-window)
"Interpolate a scroll of DELTA pixels.
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index b2fa9e06911..ae68bf989a7 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -3422,7 +3422,9 @@ initializing CC Mode. Currently (2020-06) these are `js-mode' and
;; Return a good pos (in the sense of `c-state-cache-good-pos') at the
;; lowest[*] position between POS and HERE which is syntactically equivalent
;; to HERE. This position may be HERE itself. POS is before HERE in the
- ;; buffer.
+ ;; buffer. If POS and HERE are both in the same literal, return the start
+ ;; of the literal. STATE is the parsing state at POS.
+ ;;
;; [*] We don't actually always determine this exact position, since this
;; would require a disproportionate amount of work, given that this function
;; deals only with a corner condition, and POS and HERE are typically on
@@ -3438,7 +3440,7 @@ initializing CC Mode. Currently (2020-06) these are `js-mode' and
(setq pos (point)
state s)))
(if (eq (point) here) ; HERE is in the same literal as POS
- pos
+ (nth 8 state) ; A valid good pos cannot be in a literal.
(setq s (parse-partial-sexp pos here (1+ (car state)) nil state nil))
(cond
((> (car s) (car state)) ; Moved into a paren between POS and HERE
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index 6753cf0b027..2c5f4687ac7 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -1520,7 +1520,8 @@ to `compilation-error-regexp-alist' if RULES is nil."
;; FIXME-omake: Doing it here seems wrong, at least it should depend on
;; whether or not omake's own error messages are recognized.
(cond
- ((not omake-included) nil)
+ ((or (not omake-included) (not pat))
+ nil)
((string-match "\\`\\([^^]\\|\\^\\( \\*\\|\\[\\)\\)" pat)
nil) ;; Not anchored or anchored but already allows empty spaces.
(t (setq pat (concat "^\\(?: \\)?" (substring pat 1)))))
@@ -1539,7 +1540,7 @@ to `compilation-error-regexp-alist' if RULES is nil."
(error "HYPERLINK should be an integer: %s" (nth 5 item)))
(goto-char start)
- (while (re-search-forward pat end t)
+ (while (and pat (re-search-forward pat end t))
(when (setq props (compilation-error-properties
file line end-line col end-col
(or type 2) fmt rule))
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index a4088fa4676..775b6ebab47 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -237,6 +237,26 @@ Comments in the form will be lost."
(if (bolp) (delete-char -1))
(indent-region start (point)))))
+(defun elisp-mode-syntax-propertize (start end)
+ (goto-char start)
+ (let ((case-fold-search nil))
+ (funcall
+ (syntax-propertize-rules
+ ;; Empty symbol.
+ ("##" (0 (unless (nth 8 (syntax-ppss))
+ (string-to-syntax "_"))))
+ ;; Unicode character names. (The longest name is 88 characters
+ ;; long.)
+ ("\\?\\\\N{[-A-Za-z0-9 ]\\{,100\\}}"
+ (0 (unless (nth 8 (syntax-ppss))
+ (string-to-syntax "_"))))
+ ((rx "#" (or (seq (group-n 1 "&" (+ digit)) ?\") ; Bool-vector.
+ (seq (group-n 1 "s") "(") ; Record.
+ (seq (group-n 1 (+ "^")) "["))) ; Char-table.
+ (1 (unless (save-excursion (nth 8 (syntax-ppss (match-beginning 0))))
+ (string-to-syntax "'")))))
+ start end)))
+
(defcustom emacs-lisp-mode-hook nil
"Hook run when entering Emacs Lisp mode."
:options '(eldoc-mode imenu-add-menubar-index checkdoc-minor-mode)
@@ -310,6 +330,7 @@ be used instead.
#'elisp-eldoc-var-docstring nil t)
(add-hook 'xref-backend-functions #'elisp--xref-backend nil t)
(setq-local project-vc-external-roots-function #'elisp-load-path-roots)
+ (setq-local syntax-propertize-function #'elisp-mode-syntax-propertize)
(add-hook 'completion-at-point-functions
#'elisp-completion-at-point nil 'local)
(add-hook 'flymake-diagnostic-functions #'elisp-flymake-checkdoc nil t)
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 11ed732d282..cb4be10f5cc 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -1297,7 +1297,7 @@ Called from a program, START and END specify the region to indent."
;; Don't mess with strings, unless it's the
;; enclosing set of quotes or a docstring.
(or (not (python-syntax-context 'string))
- (eq
+ (equal
(syntax-after
(+ (1- (point))
(current-indentation)
@@ -2646,6 +2646,7 @@ banner and the initial prompt are received separately."
(defun python-comint-postoutput-scroll-to-bottom (output)
"Faster version of `comint-postoutput-scroll-to-bottom'.
Avoids `recenter' calls until OUTPUT is completely sent."
+ (declare (obsolete nil "29.1")) ; Not used.
(when (and (not (string= "" output))
(python-shell-comint-end-of-output-p
(ansi-color-filter-apply output)))
@@ -2951,11 +2952,11 @@ variable.
(setq-local comint-output-filter-functions
'(ansi-color-process-output
python-shell-comint-watch-for-first-prompt-output-filter
- python-comint-postoutput-scroll-to-bottom
comint-watch-for-password-prompt))
(setq-local comint-highlight-input nil)
(setq-local compilation-error-regexp-alist
python-shell-compilation-regexp-alist)
+ (setq-local scroll-conservatively 1)
(add-hook 'completion-at-point-functions
#'python-shell-completion-at-point nil 'local)
(define-key inferior-python-mode-map "\t"
diff --git a/lisp/server.el b/lisp/server.el
index 763cf27f7ac..8f47a99a31a 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -1367,7 +1367,7 @@ The following commands are accepted by the client:
((functionp initial-buffer-choice)
(funcall initial-buffer-choice)))))
(switch-to-buffer
- (if (buffer-live-p buf) buf (get-buffer-create "*scratch*"))
+ (if (buffer-live-p buf) buf (get-scratch-buffer-create))
'norecord)))
;; Delete the client if necessary.
diff --git a/lisp/simple.el b/lisp/simple.el
index 861d9eefde9..edcc226bfa8 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -10213,16 +10213,24 @@ This is an integer indicating the UTC offset in seconds, i.e.,
the number of seconds east of Greenwich.")
)
+(defun get-scratch-buffer-create ()
+ "Return the \*scratch\* buffer, creating a new one if needed."
+ (or (get-buffer "*scratch*")
+ (let ((scratch (get-buffer-create "*scratch*")))
+ ;; Don't touch the buffer contents or mode unless we know that
+ ;; we just created it.
+ (with-current-buffer scratch
+ (when initial-scratch-message
+ (insert (substitute-command-keys initial-scratch-message))
+ (set-buffer-modified-p nil))
+ (funcall initial-major-mode))
+ scratch)))
+
(defun scratch-buffer ()
"Switch to the \*scratch\* buffer.
If the buffer doesn't exist, create it first."
(interactive)
- (if (get-buffer "*scratch*")
- (pop-to-buffer-same-window "*scratch*")
- (pop-to-buffer-same-window (get-buffer-create "*scratch*"))
- (when initial-scratch-message
- (insert initial-scratch-message))
- (funcall initial-major-mode)))
+ (pop-to-buffer-same-window (get-scratch-buffer-create)))
diff --git a/lisp/startup.el b/lisp/startup.el
index c7cf86a01e5..279dfa013c3 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -1236,6 +1236,14 @@ please check its value")
(t
(setq argval nil
argi orig-argi)))))
+
+ ;; We handle "-scripteval" further down, but we have to
+ ;; inhibit loading the user init file first. (This is for
+ ;; "emacs -x" handling.)
+ (when (equal argi "-scripteval")
+ (setq init-file-user nil
+ noninteractive t))
+
(cond
;; The --display arg is handled partly in C, partly in Lisp.
;; When it shows up here, we just put it back to be handled
@@ -2355,7 +2363,7 @@ If you have no Meta key, you may instead type ESC followed by the character.)"))
(insert "\t\t")
(insert-button "Open *scratch* buffer"
'action (lambda (_button) (switch-to-buffer
- (startup--get-buffer-create-scratch)))
+ (get-scratch-buffer-create)))
'follow-link t)
(insert "\n")
(save-restriction
@@ -2487,12 +2495,6 @@ A fancy display is used on graphic displays, normal otherwise."
(defalias 'about-emacs 'display-about-screen)
(defalias 'display-splash-screen 'display-startup-screen)
-(defun startup--get-buffer-create-scratch ()
- (or (get-buffer "*scratch*")
- (with-current-buffer (get-buffer-create "*scratch*")
- (set-buffer-major-mode (current-buffer))
- (current-buffer))))
-
;; This avoids byte-compiler warning in the unexec build.
(declare-function pdumper-stats "pdumper.c" ())
@@ -2784,7 +2786,7 @@ nil default-directory" name)
(when (eq initial-buffer-choice t)
;; When `initial-buffer-choice' equals t make sure that *scratch*
;; exists.
- (startup--get-buffer-create-scratch))
+ (get-scratch-buffer-create))
;; If *scratch* exists and is empty, insert initial-scratch-message.
;; Do this before switching to *scratch* below to handle bug#9605.
@@ -2808,7 +2810,7 @@ nil default-directory" name)
((functionp initial-buffer-choice)
(funcall initial-buffer-choice))
((eq initial-buffer-choice t)
- (startup--get-buffer-create-scratch))
+ (get-scratch-buffer-create))
(t
(error "`initial-buffer-choice' must be a string, a function, or t")))))
(unless (buffer-live-p buf)
diff --git a/lisp/subr.el b/lisp/subr.el
index dec3b9190ed..54c9f35264d 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -207,6 +207,39 @@ Also see `local-variable-p'."
(:success t)
(void-variable nil)))
+(defmacro buffer-local-set-state (&rest pairs)
+ "Like `setq-local', but allow restoring the previous state of locals later.
+This macro returns an object that can be passed to `buffer-local-restore-state'
+in order to restore the state of the local variables set via this macro.
+
+\(fn [VARIABLE VALUE]...)"
+ (declare (debug setq))
+ (unless (zerop (mod (length pairs) 2))
+ (error "PAIRS must have an even number of variable/value members"))
+ `(prog1
+ (buffer-local-set-state--get ',pairs)
+ (setq-local ,@pairs)))
+
+(defun buffer-local-set-state--get (pairs)
+ (let ((states nil))
+ (while pairs
+ (push (list (car pairs)
+ (and (boundp (car pairs))
+ (local-variable-p (car pairs)))
+ (and (boundp (car pairs))
+ (symbol-value (car pairs))))
+ states)
+ (setq pairs (cddr pairs)))
+ (nreverse states)))
+
+(defun buffer-local-restore-state (states)
+ "Restore values of buffer-local variables recorded in STATES.
+STATES should be an object returned by `buffer-local-set-state'."
+ (pcase-dolist (`(,variable ,local ,value) states)
+ (if local
+ (set variable value)
+ (kill-local-variable variable))))
+
(defmacro push (newelt place)
"Add NEWELT to the list stored in the generalized variable PLACE.
This is morally equivalent to (setf PLACE (cons NEWELT PLACE)),
@@ -4569,8 +4602,9 @@ of that nature."
(unwind-protect
(progn
,@body)
- (unless ,modified
- (restore-buffer-modified-p nil))))))
+ (when (or (not ,modified)
+ (eq ,modified 'autosaved))
+ (restore-buffer-modified-p ,modified))))))
(defmacro with-output-to-string (&rest body)
"Execute BODY, return the text it sent to `standard-output', as a string."
diff --git a/lisp/term.el b/lisp/term.el
index 3e05d529cd7..640478b59a2 100644
--- a/lisp/term.el
+++ b/lisp/term.el
@@ -918,6 +918,13 @@ is buffer-local."
:type 'integer
:version "27.1")
+(defcustom term-bind-function-keys nil
+ "If nil, don't alter <f1>, <f2> and so on.
+If non-nil, bind these keys in `term-mode' and send them to the
+underlying shell."
+ :type 'boolean
+ :version "29.1")
+
;; Set up term-raw-map, etc.
@@ -958,6 +965,10 @@ is buffer-local."
(define-key map [next] 'term-send-next)
(define-key map [xterm-paste] #'term--xterm-paste)
(define-key map [?\C-/] #'term-send-C-_)
+
+ (when term-bind-function-keys
+ (dotimes (key 21)
+ (keymap-set map (format "<f%d>" key) #'term-send-function-key)))
map)
"Keyboard map for sending characters directly to the inferior process.")
@@ -1411,6 +1422,26 @@ Entry to this mode runs the hooks on `term-mode-hook'."
(defun term-send-del () (interactive) (term-send-raw-string "\e[3~"))
(defun term-send-backspace () (interactive) (term-send-raw-string "\C-?"))
(defun term-send-C-_ () (interactive) (term-send-raw-string "\C-_"))
+
+(defun term-send-function-key ()
+ "If bound to a function key, this will send that key to the underlying shell."
+ (interactive)
+ (let ((key (this-command-keys-vector)))
+ (when (and (= (length key) 1)
+ (symbolp (elt key 0)))
+ (let ((name (symbol-name (elt key 0))))
+ (when (string-match "\\`f\\([0-9]++\\)\\'" name)
+ (let* ((num (string-to-number (match-string 1 name)))
+ (ansi
+ (cond
+ ((<= num 5) (+ num 10))
+ ((<= num 10) (+ num 11))
+ ((<= num 14) (+ num 12))
+ ((<= num 16) (+ num 13))
+ ((<= num 20) (+ num 14)))))
+ (when ansi
+ (term-send-raw-string (format "\e[%d~" ansi)))))))))
+
(defun term-char-mode ()
"Switch to char (\"raw\") sub-mode of term mode.
diff --git a/lisp/term/haiku-win.el b/lisp/term/haiku-win.el
index 5f020877325..6396779d60d 100644
--- a/lisp/term/haiku-win.el
+++ b/lisp/term/haiku-win.el
@@ -99,6 +99,7 @@ for more details on the structure of the associations.")
"B_LINK_VISITED_COLOR" "B_LINK_ACTIVE_COLOR"
"B_STATUS_BAR_COLOR" "B_SUCCESS_COLOR" "B_FAILURE_COLOR"])
+(defvar x-colors)
;; Also update `x-colors' to take that into account.
(setq x-colors (append haiku-allowed-ui-colors x-colors))
diff --git a/lisp/term/linux.el b/lisp/term/linux.el
index 6d43e477ac9..ab5a6d8698f 100644
--- a/lisp/term/linux.el
+++ b/lisp/term/linux.el
@@ -17,6 +17,10 @@
(ignore-errors (when gpm-mouse-mode (require 't-mouse) (gpm-mouse-enable)))
+ ;; Don't translate ESC TAB to backtab as directed
+ ;; by ncurses-6.3.
+ (define-key input-decode-map "\e\t" nil)
+
;; Make Latin-1 input characters work, too.
;; Meta will continue to work, because the kernel
;; turns that into Escape.
diff --git a/lisp/textmodes/pixel-fill.el b/lisp/textmodes/pixel-fill.el
index 418d6a37c97..e47653e734a 100644
--- a/lisp/textmodes/pixel-fill.el
+++ b/lisp/textmodes/pixel-fill.el
@@ -45,9 +45,9 @@ of a line or the end of a line."
(defun pixel-fill-width (&optional columns window)
"Return the pixel width corresponding to COLUMNS in WINDOW.
-If COLUMNS in nil, use the enture window width.
+If COLUMNS is nil or omitted, use the entire window width.
-If WINDOW is nil, this defaults to the current window."
+If WINDOW is nil or omitted, this defaults to the selected window."
(unless window
(setq window (selected-window)))
(let ((frame (window-frame window)))
diff --git a/lisp/textmodes/remember.el b/lisp/textmodes/remember.el
index d65aea62862..e72f86f7db6 100644
--- a/lisp/textmodes/remember.el
+++ b/lisp/textmodes/remember.el
@@ -653,7 +653,7 @@ to turn the *scratch* buffer into your notes buffer."
(remember-notes-mode 1)
(current-buffer)))))
(when switch-to
- (switch-to-buffer buf))
+ (pop-to-buffer-same-window buf))
buf))
(defun remember-notes--kill-buffer-query ()
diff --git a/lisp/textmodes/table.el b/lisp/textmodes/table.el
index 2175900194c..fc06c4c0da1 100644
--- a/lisp/textmodes/table.el
+++ b/lisp/textmodes/table.el
@@ -753,6 +753,18 @@ the cell contents dynamically."
:type 'string
:group 'table)
+(defcustom table-latex-environment "tabular"
+ "Tabular-compatible environment to use when generating latex.
+The value should be a string suitable for use as a LaTeX environment
+that's compatible with the \"tabular\" protocol, such as \"tabular\"
+and \"longtable\"."
+ :tag "Latex environment used to export tables"
+ :type '(choice
+ (const :tag "tabular" "tabular")
+ (const :tag "longtable" "longtable")
+ string)
+ :version "29.1")
+
(defcustom table-cals-thead-rows 1
"Number of top rows to become header rows in CALS table."
:tag "CALS Header Rows"
@@ -3025,7 +3037,8 @@ CALS (DocBook DTD):
"")))
((eq language 'latex)
(insert (format "%% This LaTeX table template is generated by emacs %s\n" emacs-version)
- "\\begin{tabular}{|" (apply #'concat (make-list (length col-list) "l|")) "}\n"
+ "\\begin{" table-latex-environment "}{|"
+ (apply #'concat (make-list (length col-list) "l|")) "}\n"
"\\hline\n"))
((eq language 'cals)
(insert (format "<!-- This CALS table template is generated by emacs %s -->\n" emacs-version)
@@ -3051,7 +3064,7 @@ CALS (DocBook DTD):
((eq language 'html)
(insert "</table>\n"))
((eq language 'latex)
- (insert "\\end{tabular}\n"))
+ (insert "\\end{" table-latex-environment "}\n"))
((eq language 'cals)
(set-marker-insertion-type (table-get-source-info 'colspec-marker) t) ;; insert before
(save-excursion
diff --git a/lisp/textmodes/word-wrap-mode.el b/lisp/textmodes/word-wrap-mode.el
index 1459a3395ca..c354fc773a7 100644
--- a/lisp/textmodes/word-wrap-mode.el
+++ b/lisp/textmodes/word-wrap-mode.el
@@ -60,26 +60,15 @@ The characters to break on are defined by `word-wrap-whitespace-characters'."
(if word-wrap-whitespace-mode
(progn
(setq-local word-wrap-mode--previous-state
- (list (category-table)
- (local-variable-p 'word-wrap-by-category)
- word-wrap-by-category
- (local-variable-p 'word-wrap)
- word-wrap))
+ (cons (category-table)
+ (buffer-local-set-state
+ word-wrap-by-category t
+ word-wrap t)))
(set-category-table (copy-category-table))
(dolist (char word-wrap-whitespace-characters)
- (modify-category-entry char ?|))
- (setq-local word-wrap-by-category t
- word-wrap t))
- (pcase-let ((`(,table ,lby-cat ,by-cat
- ,lwrap ,wrap)
- word-wrap-mode--previous-state))
- (if lby-cat
- (setq-local word-wrap-by-category by-cat)
- (kill-local-variable 'word-wrap-by-category))
- (if lwrap
- (setq-local word-wrap wrap)
- (kill-local-variable 'word-wrap))
- (set-category-table table))))
+ (modify-category-entry char ?|)))
+ (set-category-table (car word-wrap-mode--previous-state))
+ (buffer-local-restore-state (cdr word-wrap-mode--previous-state))))
;;;###autoload
(define-globalized-minor-mode global-word-wrap-whitespace-mode
diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el
index b41def2aff3..040a9a63c5a 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -3431,6 +3431,9 @@ Without an argument, it saves customized diff argument, if available
))
(defun ediff-show-diff-output (arg)
+ "With prefix argument ARG, show plain diff output.
+Without an argument, save the customized diff argument, if available
+(and plain output, if customized output was not generated)."
(interactive "P")
(ediff-barf-if-not-control-buffer)
(ediff-compute-custom-diffs-maybe)
@@ -3438,7 +3441,10 @@ Without an argument, it saves customized diff argument, if available
(ediff-skip-unsuitable-frames ' ok-unsplittable))
(let ((buf (cond ((and arg (ediff-buffer-live-p ediff-diff-buffer))
ediff-diff-buffer)
- ((ediff-buffer-live-p ediff-custom-diff-buffer)
+ ((and (ediff-buffer-live-p ediff-custom-diff-buffer)
+ ;; We may not have gotten a custom output if
+ ;; we're working on unsaved buffers.
+ (> (buffer-size ediff-custom-diff-buffer) 0))
ediff-custom-diff-buffer)
((ediff-buffer-live-p ediff-diff-buffer)
ediff-diff-buffer)
diff --git a/lisp/vc/log-view.el b/lisp/vc/log-view.el
index 9952345db50..415b1564eda 100644
--- a/lisp/vc/log-view.el
+++ b/lisp/vc/log-view.el
@@ -134,11 +134,7 @@
"n" #'log-view-msg-next
"p" #'log-view-msg-prev
"TAB" #'log-view-msg-next
- "<backtab>" #'log-view-msg-prev
- "N" #'log-view-file-next
- "P" #'log-view-file-prev
- "M-n" #'log-view-file-next
- "M-p" #'log-view-file-prev)
+ "<backtab>" #'log-view-msg-prev)
(easy-menu-define log-view-mode-menu log-view-mode-map
"Log-View Display Menu."
@@ -166,9 +162,15 @@
["Previous Log Entry" log-view-msg-prev
:help "Go to the previous count'th log message"]
["Next File" log-view-file-next
- :help "Go to the next count'th file"]
+ :help "Go to the next count'th file"
+ :active (derived-mode-p vc-cvs-log-view-mode
+ vc-rcs-log-view-mode
+ vc-sccs-log-view-mode)]
["Previous File" log-view-file-prev
- :help "Go to the previous count'th file"]))
+ :help "Go to the previous count'th file"
+ :active (derived-mode-p vc-cvs-log-view-mode
+ vc-rcs-log-view-mode
+ vc-sccs-log-view-mode)]))
(defvar log-view-mode-hook nil
"Hook run at the end of `log-view-mode'.")
diff --git a/lisp/vc/vc-cvs.el b/lisp/vc/vc-cvs.el
index 8f06d5a847a..1f81ff2e0fe 100644
--- a/lisp/vc/vc-cvs.el
+++ b/lisp/vc/vc-cvs.el
@@ -26,6 +26,7 @@
(require 'vc-rcs)
(eval-when-compile (require 'vc))
+(require 'log-view)
(declare-function vc-checkout "vc" (file &optional rev))
(declare-function vc-expand-dirs "vc" (file-or-dir-list backend))
@@ -1257,6 +1258,14 @@ ignore file."
(if sort (sort-lines nil (point-min) (point-max)))
(save-buffer)))))
+(defvar-keymap vc-cvs-log-view-mode-map
+ "N" #'log-view-file-next
+ "P" #'log-view-file-prev
+ "M-n" #'log-view-file-next
+ "M-p" #'log-view-file-prev)
+
+(define-derived-mode vc-cvs-log-view-mode log-view-mode "CVS-Log-View")
+
(provide 'vc-cvs)
;;; vc-cvs.el ends here
diff --git a/lisp/vc/vc-rcs.el b/lisp/vc/vc-rcs.el
index 170f5c8d464..0a2b8fa53c3 100644
--- a/lisp/vc/vc-rcs.el
+++ b/lisp/vc/vc-rcs.el
@@ -40,6 +40,7 @@
(eval-when-compile
(require 'cl-lib)
(require 'vc))
+(require 'log-view)
(declare-function vc-read-revision "vc"
(prompt &optional files backend default initial-input))
@@ -1456,6 +1457,14 @@ The `:insn' key is a keyword to distinguish it as a vc-rcs.el extension."
`((headers ,desc ,@headers)
(revisions ,@revs)))))
+(defvar-keymap vc-rcs-log-view-mode-map
+ "N" #'log-view-file-next
+ "P" #'log-view-file-prev
+ "M-n" #'log-view-file-next
+ "M-p" #'log-view-file-prev)
+
+(define-derived-mode vc-rcs-log-view-mode log-view-mode "RCS-Log-View")
+
(provide 'vc-rcs)
;;; vc-rcs.el ends here
diff --git a/lisp/vc/vc-sccs.el b/lisp/vc/vc-sccs.el
index 1035ee9ce9d..9622bf5e097 100644
--- a/lisp/vc/vc-sccs.el
+++ b/lisp/vc/vc-sccs.el
@@ -27,6 +27,7 @@
(eval-when-compile
(require 'vc))
+(require 'log-view)
;;;
;;; Customization options
@@ -518,6 +519,14 @@ If NAME is nil or a revision number string it's just passed through."
(file-name-directory (vc-master-name file))))
(vc-parse-buffer (concat name "\t:\t" file "\t\\(.+\\)") 1))))
+(defvar-keymap vc-sccs-log-view-mode-map
+ "N" #'log-view-file-next
+ "P" #'log-view-file-prev
+ "M-n" #'log-view-file-next
+ "M-p" #'log-view-file-prev)
+
+(define-derived-mode vc-sccs-log-view-mode log-view-mode "SCCS-Log-View")
+
(provide 'vc-sccs)
;;; vc-sccs.el ends here
diff --git a/lisp/window.el b/lisp/window.el
index 9f787846124..dd16b83377b 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -4886,10 +4886,7 @@ the buffer `*scratch*', creating it if necessary."
(setq frame (or frame (selected-frame)))
(or (get-next-valid-buffer (nreverse (buffer-list frame))
buffer visible-ok frame)
- (get-buffer "*scratch*")
- (let ((scratch (get-buffer-create "*scratch*")))
- (set-buffer-major-mode scratch)
- scratch)))
+ (get-scratch-buffer-create)))
(defcustom frame-auto-hide-function #'iconify-frame
"Function called to automatically hide frames.
@@ -8621,12 +8618,13 @@ If BUFFER-OR-NAME is nil, return the buffer returned by
`other-buffer'. Else, if a buffer specified by BUFFER-OR-NAME
exists, return that buffer. If no such buffer exists, create a
buffer with the name BUFFER-OR-NAME and return that buffer."
- (if buffer-or-name
- (or (get-buffer buffer-or-name)
- (let ((buffer (get-buffer-create buffer-or-name)))
- (set-buffer-major-mode buffer)
- buffer))
- (other-buffer)))
+ (pcase buffer-or-name
+ ('nil (other-buffer))
+ ("*scratch*" (get-scratch-buffer-create))
+ (_ (or (get-buffer buffer-or-name)
+ (let ((buffer (get-buffer-create buffer-or-name)))
+ (set-buffer-major-mode buffer)
+ buffer)))))
(defcustom switch-to-buffer-preserve-window-point t
"If non-nil, `switch-to-buffer' tries to preserve `window-point'.
@@ -10031,6 +10029,11 @@ When point is already on that position, then signal an error."
(defun scroll-up-command (&optional arg)
"Scroll text of selected window upward ARG lines; or near full screen if no ARG.
+Interactively, giving this command a numerical prefix will scroll
+up by that many lines (and down by that many lines if the number
+is negative). Without a prefix, scroll up by a full screen.
+If given a `C-u -' prefix, scroll a full page down instead.
+
If `scroll-error-top-bottom' is non-nil and `scroll-up' cannot
scroll window further, move cursor to the bottom line.
When point is already on that position, then signal an error.
@@ -10063,6 +10066,11 @@ If ARG is the atom `-', scroll downward by nearly full screen."
(defun scroll-down-command (&optional arg)
"Scroll text of selected window down ARG lines; or near full screen if no ARG.
+Interactively, giving this command a numerical prefix will scroll
+down by that many lines (and up by that many lines if the number
+is negative). Without a prefix, scroll down by a full screen.
+If given a `C-u -' prefix, scroll a full page up instead.
+
If `scroll-error-top-bottom' is non-nil and `scroll-down' cannot
scroll window further, move cursor to the top line.
When point is already on that position, then signal an error.
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el
index 47d8ae14cfc..c2498a57a13 100644
--- a/lisp/x-dnd.el
+++ b/lisp/x-dnd.el
@@ -783,7 +783,7 @@ FORMAT is 32 (not used). MESSAGE is the data part of an XClientMessageEvent."
;;; Handling drops.
-(defun x-dnd-handle-unsupported-drop (targets _x _y action _window-id _frame)
+(defun x-dnd-handle-unsupported-drop (targets _x _y action _window-id _frame _time)
"Return non-nil if the drop described by TARGETS and ACTION should not proceeed."
(not (and (or (eq action 'XdndActionCopy)
(eq action 'XdndActionMove))
diff --git a/lwlib/lwlib.c b/lwlib/lwlib.c
index 30546b60e51..863f65c915f 100644
--- a/lwlib/lwlib.c
+++ b/lwlib/lwlib.c
@@ -1324,10 +1324,14 @@ lw_separator_p (const char *label, enum menu_separator *type, int motif_p)
{
/* Old-style separator, maybe. It's a separator if it contains
only dashes. */
- while (*label == '-')
- ++label;
- separator_p = *label == 0;
- *type = SEPARATOR_SHADOW_ETCHED_IN;
+ if (*label == '-')
+ {
+ while (*label == '-')
+ ++label;
+ separator_p = *label == 0;
+
+ *type = SEPARATOR_SHADOW_ETCHED_IN;
+ }
}
return separator_p;
diff --git a/src/buffer.c b/src/buffer.c
index f8a7a4f5109..0f3061b4973 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1376,12 +1376,23 @@ No argument or nil as argument means use current buffer as BUFFER. */)
DEFUN ("buffer-modified-p", Fbuffer_modified_p, Sbuffer_modified_p,
0, 1, 0,
- doc: /* Return t if BUFFER was modified since its file was last read or saved.
-No argument or nil as argument means use current buffer as BUFFER. */)
+ doc: /* Return non-nil if BUFFER was modified since its file was last read or saved.
+No argument or nil as argument means use current buffer as BUFFER.
+
+If BUFFER has been autosaved after BUFFER was last modified, the
+symbol `autosaved' is returned. */)
(Lisp_Object buffer)
{
struct buffer *buf = decode_buffer (buffer);
- return BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf) ? Qt : Qnil;
+ if (BUF_SAVE_MODIFF (buf) < BUF_MODIFF (buf))
+ {
+ if (BUF_AUTOSAVE_MODIFF (buf) == BUF_MODIFF (buf))
+ return Qautosaved;
+ else
+ return Qt;
+ }
+ else
+ return Qnil;
}
DEFUN ("force-mode-line-update", Fforce_mode_line_update,
@@ -1436,6 +1447,11 @@ and `buffer-file-truename' are non-nil. */)
DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p,
Srestore_buffer_modified_p, 1, 1, 0,
doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's mode line.
+A nil FLAG means to mark the buffer as unmodified. A non-nil FLAG
+means mark the buffer as modified, except the special value
+`autosaved', which will instead mark the buffer as having been
+autosaved.
+
This function also locks or unlocks the file visited by the buffer,
if both `buffer-file-truename' and `buffer-file-name' are non-nil.
@@ -1475,16 +1491,19 @@ state of the current buffer. Use with care. */)
recent-auto-save-p from t to nil.
Vice versa, if FLAG is non-nil and SAVE_MODIFF>=auto_save_modified
we risk changing recent-auto-save-p from nil to t. */
- SAVE_MODIFF = (NILP (flag)
- /* FIXME: This unavoidably sets recent-auto-save-p to nil. */
- ? MODIFF
- /* Let's try to preserve recent-auto-save-p. */
- : SAVE_MODIFF < MODIFF ? SAVE_MODIFF
- /* If SAVE_MODIFF == auto_save_modified == MODIFF,
- we can either decrease SAVE_MODIFF and auto_save_modified
- or increase MODIFF. */
- : modiff_incr (&MODIFF));
-
+ if (NILP (flag))
+ /* This unavoidably sets recent-auto-save-p to nil. */
+ SAVE_MODIFF = MODIFF;
+ else
+ {
+ if (EQ (flag, Qautosaved))
+ BUF_AUTOSAVE_MODIFF (b) = MODIFF;
+ /* If SAVE_MODIFF == auto_save_modified == MODIFF, we can either
+ decrease SAVE_MODIFF and auto_save_modified or increase
+ MODIFF. */
+ else if (SAVE_MODIFF >= MODIFF)
+ SAVE_MODIFF = modiff_incr (&MODIFF);
+ }
return flag;
}
@@ -1499,6 +1518,18 @@ use current buffer as BUFFER. */)
return modiff_to_integer (BUF_MODIFF (decode_buffer (buffer)));
}
+DEFUN ("internal--set-buffer-modified-tick",
+ Finternal__set_buffer_modified_tick, Sinternal__set_buffer_modified_tick,
+ 1, 2, 0,
+ doc: /* Set BUFFER's tick counter to TICK.
+No argument or nil as argument means use current buffer as BUFFER. */)
+ (Lisp_Object tick, Lisp_Object buffer)
+{
+ CHECK_FIXNUM (tick);
+ BUF_MODIFF (decode_buffer (buffer)) = XFIXNUM (tick);
+ return Qnil;
+}
+
DEFUN ("buffer-chars-modified-tick", Fbuffer_chars_modified_tick,
Sbuffer_chars_modified_tick, 0, 1, 0,
doc: /* Return BUFFER's character-change tick counter.
@@ -1634,16 +1665,7 @@ exists, return the buffer `*scratch*' (creating it if necessary). */)
if (!NILP (notsogood))
return notsogood;
else
- {
- AUTO_STRING (scratch, "*scratch*");
- buf = Fget_buffer (scratch);
- if (NILP (buf))
- {
- buf = Fget_buffer_create (scratch, Qnil);
- Fset_buffer_major_mode (buf);
- }
- return buf;
- }
+ return safe_call (1, Qget_scratch_buffer_create);
}
/* The following function is a safe variant of Fother_buffer: It doesn't
@@ -1659,15 +1681,7 @@ other_buffer_safely (Lisp_Object buffer)
if (candidate_buffer (buf, buffer))
return buf;
- AUTO_STRING (scratch, "*scratch*");
- buf = Fget_buffer (scratch);
- if (NILP (buf))
- {
- buf = Fget_buffer_create (scratch, Qnil);
- Fset_buffer_major_mode (buf);
- }
-
- return buf;
+ return safe_call (1, Qget_scratch_buffer_create);
}
DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo,
@@ -5552,6 +5566,7 @@ syms_of_buffer (void)
DEFSYM (Qbefore_change_functions, "before-change-functions");
DEFSYM (Qafter_change_functions, "after-change-functions");
DEFSYM (Qkill_buffer_query_functions, "kill-buffer-query-functions");
+ DEFSYM (Qget_scratch_buffer_create, "get-scratch-buffer-create");
DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar");
Fput (Qvertical_scroll_bar, Qchoice, list4 (Qnil, Qt, Qleft, Qright));
@@ -6418,6 +6433,7 @@ will run for `clone-indirect-buffer' calls as well. */);
defsubr (&Sforce_mode_line_update);
defsubr (&Sset_buffer_modified_p);
defsubr (&Sbuffer_modified_tick);
+ defsubr (&Sinternal__set_buffer_modified_tick);
defsubr (&Sbuffer_chars_modified_tick);
defsubr (&Srename_buffer);
defsubr (&Sother_buffer);
@@ -6452,5 +6468,7 @@ will run for `clone-indirect-buffer' calls as well. */);
defsubr (&Soverlay_put);
defsubr (&Srestore_buffer_modified_p);
+ DEFSYM (Qautosaved, "autosaved");
+
Fput (intern_c_string ("erase-buffer"), Qdisabled, Qt);
}
diff --git a/src/dispextern.h b/src/dispextern.h
index e9b19a7f135..a7f478acdf8 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1075,6 +1075,9 @@ struct glyph_row
right-to-left paragraph. */
bool_bf reversed_p : 1;
+ /* Whether or not a stipple was drawn in this row at some point. */
+ bool_bf stipple_p : 1;
+
/* Continuation lines width at the start of the row. */
int continuation_lines_width;
diff --git a/src/dispnew.c b/src/dispnew.c
index 1dd64be4ead..795c928bc13 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -3907,7 +3907,8 @@ update_marginal_area (struct window *w, struct glyph_row *updated_row,
Value is true if display has changed. */
static bool
-update_text_area (struct window *w, struct glyph_row *updated_row, int vpos)
+update_text_area (struct window *w, struct glyph_row *updated_row, int vpos,
+ bool *partial_p)
{
struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos);
struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos);
@@ -4013,6 +4014,13 @@ update_text_area (struct window *w, struct glyph_row *updated_row, int vpos)
{
x += desired_glyph->pixel_width;
++desired_glyph, ++current_glyph, ++i;
+
+ /* Say that only a partial update was performed of
+ the current row (i.e. not all the glyphs were
+ drawn). This is used to preserve the stipple_p
+ flag of the current row inside
+ update_window_line. */
+ *partial_p = true;
}
/* Consider the case that the current row contains "xxx
@@ -4084,9 +4092,15 @@ update_text_area (struct window *w, struct glyph_row *updated_row, int vpos)
rif->write_glyphs (w, updated_row, start,
TEXT_AREA, i - start_hpos);
changed_p = 1;
+ *partial_p = true;
}
}
+ /* This means we will draw from the start, so no partial update
+ is being performed. */
+ if (!i)
+ *partial_p = false;
+
/* Write the rest. */
if (i < desired_row->used[TEXT_AREA])
{
@@ -4159,7 +4173,9 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p)
struct glyph_row *current_row = MATRIX_ROW (w->current_matrix, vpos);
struct glyph_row *desired_row = MATRIX_ROW (w->desired_matrix, vpos);
struct redisplay_interface *rif = FRAME_RIF (XFRAME (WINDOW_FRAME (w)));
- bool changed_p = 0;
+
+ /* partial_p is true if not all of desired_row was drawn. */
+ bool changed_p = 0, partial_p = 0, was_stipple;
/* A row can be completely invisible in case a desired matrix was
built with a vscroll and then make_cursor_line_fully_visible shifts
@@ -4183,7 +4199,7 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p)
}
/* Update the display of the text area. */
- if (update_text_area (w, desired_row, vpos))
+ if (update_text_area (w, desired_row, vpos, &partial_p))
{
changed_p = 1;
if (current_row->mouse_face_p)
@@ -4212,7 +4228,17 @@ update_window_line (struct window *w, int vpos, bool *mouse_face_overwritten_p)
}
/* Update current_row from desired_row. */
+ was_stipple = current_row->stipple_p;
make_current (w->desired_matrix, w->current_matrix, vpos);
+
+ /* If only a partial update was performed, any stipple already
+ displayed in MATRIX_ROW (w->current_matrix, vpos) might still be
+ there, so don't hurry to clear that flag if it's not in
+ desired_row. */
+
+ if (partial_p && was_stipple)
+ current_row->stipple_p = true;
+
return changed_p;
}
@@ -4392,7 +4418,6 @@ add_row_entry (struct glyph_row *row)
return entry;
}
-
/* Try to reuse part of the current display of W by scrolling lines.
HEADER_LINE_P means W has a header line.
@@ -4438,6 +4463,14 @@ scrolling_window (struct window *w, int tab_line_p)
struct glyph_row *d = MATRIX_ROW (desired_matrix, i);
struct glyph_row *c = MATRIX_ROW (current_matrix, i);
+ /* If there is a row with a stipple currently on the glass, give
+ up. Stipples look different depending on where on the
+ display they are drawn, so scrolling the display will produce
+ incorrect results. */
+
+ if (c->stipple_p)
+ return 0;
+
if (c->enabled_p
&& d->enabled_p
&& !d->redraw_fringe_bitmaps_p
@@ -4467,6 +4500,16 @@ scrolling_window (struct window *w, int tab_line_p)
first_old = first_new = i;
+ while (i < current_matrix->nrows - 1)
+ {
+ /* If there is a stipple after the first change, give up as
+ well. */
+ if (MATRIX_ROW (current_matrix, i)->stipple_p)
+ return 0;
+
+ ++i;
+ }
+
/* Set last_new to the index + 1 of the row that reaches the
bottom boundary in the desired matrix. Give up if we find a
disabled row before we reach the bottom boundary. */
diff --git a/src/fileio.c b/src/fileio.c
index c418036fc6e..9da14c8f541 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2718,6 +2718,20 @@ This is what happens in interactive use with M-x. */)
: Qnil);
if (!NILP (symlink_target))
Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists);
+ else if (S_ISFIFO (file_st.st_mode))
+ {
+ /* If it's a FIFO, calling `copy-file' will hang if it's a
+ inter-file system move, so do it here. (It will signal
+ an error in that case, but it won't hang in any case.) */
+ if (!NILP (ok_if_already_exists))
+ barf_or_query_if_file_exists (newname, false,
+ "rename to it",
+ FIXNUMP (ok_if_already_exists),
+ false);
+ if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) != 0)
+ report_file_errno ("Renaming", list2 (file, newname), errno);
+ return Qnil;
+ }
else
Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt);
}
@@ -5958,14 +5972,17 @@ do_auto_save_eh (Lisp_Object ignore)
DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
doc: /* Auto-save all buffers that need it.
-This is all buffers that have auto-saving enabled
-and are changed since last auto-saved.
-Auto-saving writes the buffer into a file
-so that your editing is not lost if the system crashes.
+This is all buffers that have auto-saving enabled and are changed
+since last auto-saved.
+
+Auto-saving writes the buffer into a file so that your editing is not
+lost if the system crashes.
+
This file is not the file you visited; that changes only when you save.
Normally, run the normal hook `auto-save-hook' before saving.
A non-nil NO-MESSAGE argument means do not print any message if successful.
+
A non-nil CURRENT-ONLY argument means save only current buffer. */)
(Lisp_Object no_message, Lisp_Object current_only)
{
diff --git a/src/fns.c b/src/fns.c
index 4673fde28c7..2c206c62b22 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -4113,7 +4113,7 @@ hash_table_user_defined_call (ptrdiff_t nargs, Lisp_Object *args,
return unbind_to (count, Ffuncall (nargs, args));
}
-/* Ignore HT and compare KEY1 and KEY2 using 'eql'.
+/* Ignore H and compare KEY1 and KEY2 using 'eql'.
Value is true if KEY1 and KEY2 are the same. */
static Lisp_Object
@@ -4122,7 +4122,7 @@ cmpfn_eql (Lisp_Object key1, Lisp_Object key2, struct Lisp_Hash_Table *h)
return Feql (key1, key2);
}
-/* Ignore HT and compare KEY1 and KEY2 using 'equal'.
+/* Ignore H and compare KEY1 and KEY2 using 'equal'.
Value is true if KEY1 and KEY2 are the same. */
static Lisp_Object
@@ -4132,7 +4132,7 @@ cmpfn_equal (Lisp_Object key1, Lisp_Object key2, struct Lisp_Hash_Table *h)
}
-/* Given HT, compare KEY1 and KEY2 using HT->user_cmp_function.
+/* Given H, compare KEY1 and KEY2 using H->user_cmp_function.
Value is true if KEY1 and KEY2 are the same. */
static Lisp_Object
@@ -4143,8 +4143,7 @@ cmpfn_user_defined (Lisp_Object key1, Lisp_Object key2,
return hash_table_user_defined_call (ARRAYELTS (args), args, h);
}
-/* Ignore HT and return a hash code for KEY which uses 'eq' to compare
- keys. */
+/* Ignore H and return a hash code for KEY which uses 'eq' to compare keys. */
static Lisp_Object
hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h)
@@ -4154,7 +4153,7 @@ hashfn_eq (Lisp_Object key, struct Lisp_Hash_Table *h)
return make_ufixnum (XHASH (key) ^ XTYPE (key));
}
-/* Ignore HT and return a hash code for KEY which uses 'equal' to compare keys.
+/* Ignore H and return a hash code for KEY which uses 'equal' to compare keys.
The hash code is at most INTMASK. */
static Lisp_Object
@@ -4163,7 +4162,7 @@ hashfn_equal (Lisp_Object key, struct Lisp_Hash_Table *h)
return make_ufixnum (sxhash (key));
}
-/* Ignore HT and return a hash code for KEY which uses 'eql' to compare keys.
+/* Ignore H and return a hash code for KEY which uses 'eql' to compare keys.
The hash code is at most INTMASK. */
static Lisp_Object
@@ -4172,7 +4171,7 @@ hashfn_eql (Lisp_Object key, struct Lisp_Hash_Table *h)
return (FLOATP (key) || BIGNUMP (key) ? hashfn_equal : hashfn_eq) (key, h);
}
-/* Given HT, return a hash code for KEY which uses a user-defined
+/* Given H, return a hash code for KEY which uses a user-defined
function to compare keys. */
Lisp_Object
diff --git a/src/haiku_draw_support.cc b/src/haiku_draw_support.cc
index a8d46d000a3..551af51d7c1 100644
--- a/src/haiku_draw_support.cc
+++ b/src/haiku_draw_support.cc
@@ -285,11 +285,32 @@ BView_DrawBitmap (void *view, void *bitmap, int x, int y,
BView *vw = get_view (view);
BBitmap *bm = (BBitmap *) bitmap;
- vw->PushState ();
vw->SetDrawingMode (B_OP_OVER);
vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
- vw->PopState ();
+ vw->SetDrawingMode (B_OP_COPY);
+}
+
+void
+BView_DrawBitmapTiled (void *view, void *bitmap, int x, int y,
+ int width, int height, int vx, int vy,
+ int vwidth, int vheight)
+{
+ BView *vw = get_view (view);
+ BBitmap *bm = (BBitmap *) bitmap;
+ BRect bounds = bm->Bounds ();
+
+ if (width == -1)
+ width = BE_RECT_WIDTH (bounds);
+
+ if (height == -1)
+ height = BE_RECT_HEIGHT (bounds);
+
+ vw->SetDrawingMode (B_OP_OVER);
+ vw->DrawBitmap (bm, BRect (x, y, x + width - 1, y + height - 1),
+ BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1),
+ B_TILE_BITMAP);
+ vw->SetDrawingMode (B_OP_COPY);
}
void
@@ -300,17 +321,22 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
BBitmap *bm = (BBitmap *) bitmap;
BBitmap bc (bm->Bounds (), B_RGBA32);
BRect rect (x, y, x + width - 1, y + height - 1);
+ uint32_t *bits;
+ size_t stride;
+ rgb_color low_color;
+ BRect bounds;
if (bc.InitCheck () != B_OK || bc.ImportBits (bm) != B_OK)
return;
- uint32_t *bits = (uint32_t *) bc.Bits ();
- size_t stride = bc.BytesPerRow ();
+ bits = (uint32_t *) bc.Bits ();
+ stride = bc.BytesPerRow ();
if (bm->ColorSpace () == B_GRAY1)
{
- rgb_color low_color = vw->LowColor ();
- BRect bounds = bc.Bounds ();
+ low_color = vw->LowColor ();
+ bounds = bc.Bounds ();
+
for (int y = 0; y < BE_RECT_HEIGHT (bounds); ++y)
{
for (int x = 0; x < BE_RECT_WIDTH (bounds); ++x)
@@ -323,10 +349,11 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
}
}
- vw->PushState ();
- vw->SetDrawingMode (bm->ColorSpace () == B_GRAY1 ? B_OP_OVER : B_OP_ERASE);
+ vw->SetDrawingMode ((bm->ColorSpace ()
+ == B_GRAY1)
+ ? B_OP_OVER : B_OP_ERASE);
vw->DrawBitmap (&bc, rect);
- vw->PopState ();
+ vw->SetDrawingMode (B_OP_COPY);
}
void
@@ -357,6 +384,7 @@ BView_DrawMask (void *src, void *view,
vw->SetDrawingMode (B_OP_OVER);
vw->DrawBitmap (&bm, BRect (x, y, x + width - 1, y + height - 1),
BRect (vx, vy, vx + vwidth - 1, vy + vheight - 1));
+ vw->SetDrawingMode (B_OP_COPY);
}
static BBitmap *
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
index 0ab31bc98dc..6b4951e139a 100644
--- a/src/haiku_support.cc
+++ b/src/haiku_support.cc
@@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <app/Application.h>
#include <app/Cursor.h>
#include <app/Messenger.h>
+#include <app/Roster.h>
#include <interface/GraphicsDefs.h>
#include <interface/InterfaceDefs.h>
@@ -195,10 +196,6 @@ static void *grab_view = NULL;
static BLocker grab_view_locker;
static bool drag_and_drop_in_progress;
-/* Port used to send data to the main thread while a file panel is
- active. */
-static port_id volatile current_file_panel_port;
-
/* Many places require us to lock the child frame data, and then lock
the locker of some random window. Unfortunately, locking such a
window might be delayed due to an arriving message, which then
@@ -853,8 +850,6 @@ public:
void
MessageReceived (BMessage *msg)
{
- int32 old_what = 0;
-
if (msg->WasDropped ())
{
BPoint whereto;
@@ -886,49 +881,6 @@ public:
haiku_write (MENU_BAR_SELECT_EVENT, &rq);
}
- else if (msg->what == FILE_PANEL_SELECTION
- || ((msg->FindInt32 ("old_what", &old_what) == B_OK
- && old_what == FILE_PANEL_SELECTION)))
- {
- const char *str_path, *name;
- char *file_name, *str_buf;
- BEntry entry;
- BPath path;
- entry_ref ref;
-
- file_name = NULL;
-
- if (msg->FindRef ("refs", &ref) == B_OK &&
- entry.SetTo (&ref, 0) == B_OK &&
- entry.GetPath (&path) == B_OK)
- {
- str_path = path.Path ();
-
- if (str_path)
- file_name = strdup (str_path);
- }
-
- if (msg->FindRef ("directory", &ref),
- entry.SetTo (&ref, 0) == B_OK &&
- entry.GetPath (&path) == B_OK)
- {
- name = msg->GetString ("name");
- str_path = path.Path ();
-
- if (name)
- {
- str_buf = (char *) alloca (std::strlen (str_path)
- + std::strlen (name) + 2);
- snprintf (str_buf, std::strlen (str_path)
- + std::strlen (name) + 2, "%s/%s",
- str_path, name);
- file_name = strdup (str_buf);
- }
- }
-
- write_port (current_file_panel_port, 0,
- &file_name, sizeof file_name);
- }
else
BWindow::MessageReceived (msg);
}
@@ -3026,6 +2978,125 @@ public:
}
};
+class EmacsFilePanelCallbackLooper : public BLooper
+{
+ port_id comm_port;
+
+ void
+ MessageReceived (BMessage *msg)
+ {
+ const char *str_path, *name;
+ char *file_name, *str_buf;
+ BEntry entry;
+ BPath path;
+ entry_ref ref;
+ int32 old_what;
+
+ if (msg->what == FILE_PANEL_SELECTION
+ || ((msg->FindInt32 ("old_what", &old_what) == B_OK
+ && old_what == FILE_PANEL_SELECTION)))
+ {
+ file_name = NULL;
+
+ if (msg->FindRef ("refs", &ref) == B_OK
+ && entry.SetTo (&ref, 0) == B_OK
+ && entry.GetPath (&path) == B_OK)
+ {
+ str_path = path.Path ();
+
+ if (str_path)
+ file_name = strdup (str_path);
+ }
+ else if (msg->FindRef ("directory", &ref) == B_OK
+ && entry.SetTo (&ref, 0) == B_OK
+ && entry.GetPath (&path) == B_OK)
+ {
+ name = msg->GetString ("name");
+ str_path = path.Path ();
+
+ if (name)
+ {
+ str_buf = (char *) alloca (std::strlen (str_path)
+ + std::strlen (name) + 2);
+ snprintf (str_buf, std::strlen (str_path)
+ + std::strlen (name) + 2, "%s/%s",
+ str_path, name);
+ file_name = strdup (str_buf);
+ }
+ }
+
+ write_port (comm_port, 0, &file_name, sizeof file_name);
+ }
+
+ BLooper::MessageReceived (msg);
+ }
+
+public:
+ EmacsFilePanelCallbackLooper (void) : BLooper ()
+ {
+ comm_port = create_port (1, "file panel port");
+ }
+
+ ~EmacsFilePanelCallbackLooper (void)
+ {
+ delete_port (comm_port);
+ }
+
+ char *
+ ReadFileName (void (*process_pending_signals_function) (void))
+ {
+ object_wait_info infos[2];
+ ssize_t status;
+ int32 reply_type;
+ char *file_name;
+
+ file_name = NULL;
+
+ infos[0].object = port_application_to_emacs;
+ infos[0].type = B_OBJECT_TYPE_PORT;
+ infos[0].events = B_EVENT_READ;
+
+ infos[1].object = comm_port;
+ infos[1].type = B_OBJECT_TYPE_PORT;
+ infos[1].events = B_EVENT_READ;
+
+ while (true)
+ {
+ status = wait_for_objects (infos, 2);
+
+ if (status == B_INTERRUPTED || status == B_WOULD_BLOCK)
+ continue;
+
+ if (infos[0].events & B_EVENT_READ)
+ process_pending_signals_function ();
+
+ if (infos[1].events & B_EVENT_READ)
+ {
+ status = read_port (comm_port,
+ &reply_type, &file_name,
+ sizeof file_name);
+
+ if (status < B_OK)
+ file_name = NULL;
+
+ goto out;
+ }
+
+ infos[0].events = B_EVENT_READ;
+ infos[1].events = B_EVENT_READ;
+ }
+
+ out:
+ return file_name;
+ }
+
+ status_t
+ InitCheck (void)
+ {
+ return comm_port >= B_OK ? B_OK : comm_port;
+ }
+};
+
static int32
start_running_application (void *data)
{
@@ -3265,15 +3336,18 @@ BWindow_activate (void *window)
/* Return the pixel dimensions of the main screen in WIDTH and
HEIGHT. */
void
-BScreen_px_dim (int *width, int *height)
+be_get_screen_dimensions (int *width, int *height)
{
BScreen screen;
+ BRect frame;
+
if (!screen.IsValid ())
gui_abort ("Invalid screen");
- BRect frame = screen.Frame ();
- *width = frame.right - frame.left;
- *height = frame.bottom - frame.top;
+ frame = screen.Frame ();
+
+ *width = 1 + frame.right - frame.left;
+ *height = 1 + frame.bottom - frame.top;
}
/* Resize VIEW to WIDTH, HEIGHT. */
@@ -3526,17 +3600,6 @@ BBitmap_import_fringe_bitmap (void *bitmap, unsigned short *bits, int wd, int h)
}
}
-void
-BBitmap_import_mono_bits (void *bitmap, void *bits, int wd, int h)
-{
- BBitmap *bmp = (BBitmap *) bitmap;
-
- if (wd % 8)
- wd += 8 - (wd % 8);
-
- bmp->ImportBits (bits, wd / 8 * h, wd / 8, 0, B_GRAY1);
-}
-
/* Make a scrollbar at X, Y known to the view VIEW. */
void
BView_publish_scroll_bar (void *view, int x, int y, int width, int height)
@@ -4129,25 +4192,32 @@ BAlert_delete (void *alert)
delete (BAlert *) alert;
}
-/* Place the resolution of the monitor in DPI in RSSX and RSSY. */
+/* Place the resolution of the monitor in DPI in X_OUT and Y_OUT. */
void
-BScreen_res (double *rrsx, double *rrsy)
+be_get_display_resolution (double *x_out, double *y_out)
{
BScreen s (B_MAIN_SCREEN_ID);
+ monitor_info i;
+ double x_inches, y_inches;
+ BRect frame;
+
if (!s.IsValid ())
gui_abort ("Invalid screen for resolution checks");
- monitor_info i;
if (s.GetMonitorInfo (&i) == B_OK)
{
- *rrsx = (double) i.width / (double) 2.54;
- *rrsy = (double) i.height / (double) 2.54;
- }
- else
- {
- *rrsx = 72.27;
- *rrsy = 72.27;
+ frame = s.Frame ();
+
+ x_inches = (double) i.width * 25.4;
+ y_inches = (double) i.height * 25.4;
+
+ *x_out = (double) BE_RECT_WIDTH (frame) / x_inches;
+ *y_out = (double) BE_RECT_HEIGHT (frame) / y_inches;
+ return;
}
+
+ *x_out = 72.0;
+ *y_out = 72.0;
}
/* Add WINDOW to OTHER_WINDOW's subset and parent it to
@@ -4393,23 +4463,23 @@ be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p,
const char *prompt,
void (*process_pending_signals_function) (void))
{
- BWindow *w, *panel_window;
+ BWindow *panel_window;
BEntry path;
BMessage msg (FILE_PANEL_SELECTION);
BFilePanel panel (open_p ? B_OPEN_PANEL : B_SAVE_PANEL,
NULL, NULL, (dir_only_p
? B_DIRECTORY_NODE
: B_FILE_NODE | B_DIRECTORY_NODE));
- object_wait_info infos[2];
- ssize_t status;
- int32 reply_type;
char *file_name;
+ EmacsFilePanelCallbackLooper *looper;
- current_file_panel_port = create_port (1, "file panel port");
- file_name = NULL;
+ looper = new EmacsFilePanelCallbackLooper;
- if (current_file_panel_port < B_OK)
- return NULL;
+ if (looper->InitCheck () < B_OK)
+ {
+ delete looper;
+ return NULL;
+ }
if (default_dir)
{
@@ -4417,11 +4487,8 @@ be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p,
default_dir = NULL;
}
- w = (BWindow *) window;
panel_window = panel.Window ();
- panel.SetMessage (&msg);
-
if (default_dir)
panel.SetPanelDirectory (&path);
@@ -4432,45 +4499,16 @@ be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p,
panel_window->SetFeel (B_MODAL_APP_WINDOW_FEEL);
panel.SetHideWhenDone (false);
- panel.SetTarget (BMessenger (w));
+ panel.SetTarget (BMessenger (looper));
+ panel.SetMessage (&msg);
panel.Show ();
- infos[0].object = port_application_to_emacs;
- infos[0].type = B_OBJECT_TYPE_PORT;
- infos[0].events = B_EVENT_READ;
-
- infos[1].object = current_file_panel_port;
- infos[1].type = B_OBJECT_TYPE_PORT;
- infos[1].events = B_EVENT_READ;
-
- while (true)
- {
- status = wait_for_objects (infos, 2);
+ looper->Run ();
+ file_name = looper->ReadFileName (process_pending_signals_function);
- if (status == B_INTERRUPTED || status == B_WOULD_BLOCK)
- continue;
-
- if (infos[0].events & B_EVENT_READ)
- process_pending_signals_function ();
-
- if (infos[1].events & B_EVENT_READ)
- {
- status = read_port (current_file_panel_port,
- &reply_type, &file_name,
- sizeof file_name);
-
- if (status < B_OK)
- file_name = NULL;
-
- goto out;
- }
-
- infos[0].events = B_EVENT_READ;
- infos[1].events = B_EVENT_READ;
- }
+ if (looper->Lock ())
+ looper->Quit ();
- out:
- delete_port (current_file_panel_port);
return file_name;
}
@@ -5019,3 +5057,51 @@ be_select_font (void (*process_pending_signals_function) (void),
return true;
}
+
+void
+BWindow_set_sticky (void *window, bool sticky)
+{
+ BWindow *w = (BWindow *) window;
+
+ if (w->LockLooper ())
+ {
+ w->SetFlags (sticky ? (w->Flags ()
+ | B_SAME_POSITION_IN_ALL_WORKSPACES)
+ : w->Flags () & ~B_SAME_POSITION_IN_ALL_WORKSPACES);
+
+ w->UnlockLooper ();
+ }
+}
+
+status_t
+be_roster_launch (const char *type, const char *file, char **cargs,
+ ptrdiff_t nargs, void *message, team_id *team_id)
+{
+ BEntry entry;
+ entry_ref ref;
+
+ if (type)
+ {
+ if (message)
+ return be_roster->Launch (type, (BMessage *) message,
+ team_id);
+
+ return be_roster->Launch (type, (nargs > INT_MAX
+ ? INT_MAX : nargs),
+ cargs, team_id);
+ }
+
+ if (entry.SetTo (file) != B_OK)
+ return B_ERROR;
+
+ if (entry.GetRef (&ref) != B_OK)
+ return B_ERROR;
+
+ if (message)
+ return be_roster->Launch (&ref, (BMessage *) message,
+ team_id);
+
+ return be_roster->Launch (&ref, (nargs > INT_MAX
+ ? INT_MAX : nargs),
+ cargs, team_id);
+}
diff --git a/src/haiku_support.h b/src/haiku_support.h
index 0fe2af3329a..416c717546f 100644
--- a/src/haiku_support.h
+++ b/src/haiku_support.h
@@ -504,6 +504,7 @@ extern bool BWindow_is_active (void *);
extern void BWindow_set_override_redirect (void *, bool);
extern void BWindow_dimensions (void *, int *, int *);
extern void BWindow_set_z_group (void *, enum haiku_z_group);
+extern void BWindow_set_sticky (void *, bool);
extern void BWindow_Flush (void *);
extern void BFont_close (void *);
@@ -540,6 +541,8 @@ extern void BView_DrawBitmap (void *, void *, int, int, int, int, int, int,
extern void BView_DrawBitmapWithEraseOp (void *, void *, int, int, int, int);
extern void BView_DrawMask (void *, void *, int, int, int, int, int, int,
int, int, uint32_t);
+extern void BView_DrawBitmapTiled (void *, void *, int, int,
+ int, int, int, int, int, int);
extern void BView_resize_to (void *, int, int);
extern void BView_set_view_cursor (void *, void *);
@@ -549,8 +552,8 @@ extern void BView_scroll_bar_update (void *, int, int, int, int, bool);
extern void *BBitmap_transform_bitmap (void *, void *, uint32_t, double,
int, int);
-extern void BScreen_px_dim (int *, int *);
-extern void BScreen_res (double *, double *);
+extern void be_get_display_resolution (double *, double *);
+extern void be_get_screen_dimensions (int *, int *);
/* Functions for creating and freeing cursors. */
extern void *BCursor_create_default (void);
@@ -569,9 +572,7 @@ extern void BView_invalidate (void *);
extern void BView_draw_lock (void *, bool, int, int, int, int);
extern void BView_invalidate_region (void *, int, int, int, int);
extern void BView_draw_unlock (void *);
-
extern void BBitmap_import_fringe_bitmap (void *, unsigned short *, int, int);
-extern void BBitmap_import_mono_bits (void *, void *, int, int);
extern void haiku_font_pattern_free (struct haiku_font_pattern *);
@@ -689,6 +690,8 @@ extern bool be_select_font (void (*) (void), bool (*) (void),
int *, bool, int, int, int);
extern int be_find_font_indices (struct haiku_font_pattern *, int *, int *);
+extern status_t be_roster_launch (const char *, const char *, char **,
+ ptrdiff_t, void *, team_id *);
#ifdef __cplusplus
}
diff --git a/src/haikufns.c b/src/haikufns.c
index e88ded23ffe..8596317de25 100644
--- a/src/haikufns.c
+++ b/src/haikufns.c
@@ -1203,7 +1203,11 @@ compute_tip_xy (struct frame *f,
/* Default min and max values. */
min_x = 0;
min_y = 0;
- BScreen_px_dim (&max_x, &max_y);
+
+ be_get_screen_dimensions (&max_x, &max_y);
+
+ max_x = max_x - 1;
+ max_y = max_y - 1;
block_input ();
BView_get_mouse (FRAME_HAIKU_VIEW (f), &x, &y);
@@ -1779,6 +1783,15 @@ haiku_set_inhibit_double_buffering (struct frame *f,
unblock_input ();
}
+static void
+haiku_set_sticky (struct frame *f, Lisp_Object new_value,
+ Lisp_Object old_value)
+{
+ block_input ();
+ BWindow_set_sticky (FRAME_HAIKU_WINDOW (f), !NILP (new_value));
+ unblock_input ();
+}
+
DEFUN ("haiku-set-mouse-absolute-pixel-position",
@@ -1917,7 +1930,7 @@ DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
int width, height;
check_haiku_display_info (terminal);
- BScreen_px_dim (&width, &height);
+ be_get_screen_dimensions (&width, &height);
return make_fixnum (width);
}
@@ -1930,7 +1943,7 @@ DEFUN ("x-display-pixel-height", Fx_display_pixel_height, Sx_display_pixel_heigh
int width, height;
check_haiku_display_info (terminal);
- BScreen_px_dim (&width, &height);
+ be_get_screen_dimensions (&width, &height);
return make_fixnum (width);
}
@@ -1941,7 +1954,7 @@ DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1,
struct haiku_display_info *dpyinfo = check_haiku_display_info (terminal);
int width, height;
- BScreen_px_dim (&width, &height);
+ be_get_screen_dimensions (&width, &height);
return make_fixnum (height / (dpyinfo->resy / 25.4));
}
@@ -1953,7 +1966,7 @@ DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
struct haiku_display_info *dpyinfo = check_haiku_display_info (terminal);
int width, height;
- BScreen_px_dim (&width, &height);
+ be_get_screen_dimensions (&width, &height);
return make_fixnum (width / (dpyinfo->resx / 25.4));
}
@@ -2709,7 +2722,7 @@ frame_parm_handler haiku_frame_parm_handlers[] =
gui_set_fullscreen,
gui_set_font_backend,
gui_set_alpha,
- NULL, /* set sticky */
+ haiku_set_sticky,
NULL, /* set tool bar pos */
haiku_set_inhibit_double_buffering,
haiku_set_undecorated,
diff --git a/src/haikufont.c b/src/haikufont.c
index f8cf45284d0..54f11c6e413 100644
--- a/src/haikufont.c
+++ b/src/haikufont.c
@@ -1084,8 +1084,8 @@ haikufont_draw (struct glyph_string *s, int from, int to,
s->first_glyph->slice.glyphless.lower_yoff
- s->first_glyph->slice.glyphless.upper_yoff;
- BView_SetHighColor (view, background);
- BView_FillRectangle (view, x, y - ascent, s->width, height);
+ haiku_draw_background_rect (s, s->face, x, y - ascent,
+ s->width, height);
s->background_filled_p = 1;
}
@@ -1231,14 +1231,11 @@ in the font selection dialog. */)
lfamily = build_string_from_utf8 (family);
lweight = (pattern.specified & FSPEC_WEIGHT
- ? haikufont_weight_to_lisp (pattern.weight)
- : Qunspecified);
+ ? haikufont_weight_to_lisp (pattern.weight) : Qnil);
lslant = (pattern.specified & FSPEC_SLANT
- ? haikufont_slant_to_lisp (pattern.slant)
- : Qunspecified);
+ ? haikufont_slant_to_lisp (pattern.slant) : Qnil);
lwidth = (pattern.specified & FSPEC_WIDTH
- ? haikufont_width_to_lisp (pattern.width)
- : Qunspecified);
+ ? haikufont_width_to_lisp (pattern.width) : Qnil);
ladstyle = (pattern.specified & FSPEC_STYLE
? intern (pattern.style) : Qnil);
lsize = (size >= 0 ? make_fixnum (size) : Qnil);
diff --git a/src/haikuselect.c b/src/haikuselect.c
index a186acc66ff..8ce71822983 100644
--- a/src/haikuselect.c
+++ b/src/haikuselect.c
@@ -275,7 +275,7 @@ haiku_message_to_lisp (void *message)
if (!pbuf)
memory_full (SIZE_MAX);
- t1 = build_string (pbuf);
+ t1 = DECODE_FILE (build_string (pbuf));
free (pbuf);
break;
@@ -526,7 +526,8 @@ haiku_lisp_to_message (Lisp_Object obj, void *message)
case 'RREF':
CHECK_STRING (data);
- if (be_add_refs_data (message, SSDATA (name), SSDATA (data))
+ if (be_add_refs_data (message, SSDATA (name),
+ SSDATA (ENCODE_FILE (data)))
&& haiku_signal_invalid_refs)
signal_error ("Invalid file name", data);
break;
@@ -799,6 +800,88 @@ ignored if it is dropped on top of FRAME. */)
return unbind_to (idx, Qnil);
}
+DEFUN ("haiku-roster-launch", Fhaiku_roster_launch, Shaiku_roster_launch,
+ 2, 2, 0,
+ doc: /* Launch an application associated with FILE-OR-TYPE.
+Return the process ID of the application, or nil if no application was
+launched.
+
+FILE-OR-TYPE can either be a string denoting a MIME type, or a list
+with one argument FILE, denoting a file whose associated application
+will be launched.
+
+ARGS can either be a vector of strings containing the arguments that
+will be passed to the application, or a system message in the form
+accepted by `haiku-drag-message' that will be sent to the application
+after it starts. */)
+ (Lisp_Object file_or_type, Lisp_Object args)
+{
+ char **cargs;
+ char *type, *file;
+ team_id team_id;
+ status_t rc;
+ ptrdiff_t i, nargs;
+ Lisp_Object tem, canonical;
+ void *message;
+ specpdl_ref depth;
+
+ type = NULL;
+ file = NULL;
+ cargs = NULL;
+ message = NULL;
+ nargs = 0;
+ depth = SPECPDL_INDEX ();
+
+ USE_SAFE_ALLOCA;
+
+ if (STRINGP (file_or_type))
+ SAFE_ALLOCA_STRING (type, file_or_type);
+ else
+ {
+ CHECK_LIST (file_or_type);
+ tem = XCAR (file_or_type);
+ canonical = Fexpand_file_name (tem, Qnil);
+
+ CHECK_STRING (tem);
+ SAFE_ALLOCA_STRING (file, ENCODE_FILE (canonical));
+ CHECK_LIST_END (XCDR (file_or_type), file_or_type);
+ }
+
+ if (VECTORP (args))
+ {
+ nargs = ASIZE (args);
+ cargs = SAFE_ALLOCA (nargs * sizeof *cargs);
+
+ for (i = 0; i < nargs; ++i)
+ {
+ tem = AREF (args, i);
+ CHECK_STRING (tem);
+ maybe_quit ();
+
+ cargs[i] = SAFE_ALLOCA (SBYTES (tem) + 1);
+ memcpy (cargs[i], SDATA (tem), SBYTES (tem) + 1);
+ }
+ }
+ else
+ {
+ message = be_create_simple_message ();
+
+ record_unwind_protect_ptr (BMessage_delete, message);
+ haiku_lisp_to_message (args, message);
+ }
+
+ block_input ();
+ rc = be_roster_launch (type, file, cargs, nargs, message,
+ &team_id);
+ unblock_input ();
+
+ if (rc == B_OK)
+ return SAFE_FREE_UNBIND_TO (depth,
+ make_uint (team_id));
+
+ return SAFE_FREE_UNBIND_TO (depth, Qnil);
+}
+
static Lisp_Object
haiku_note_drag_motion_1 (void *data)
{
@@ -860,6 +943,7 @@ used to retrieve the current position of the mouse. */);
defsubr (&Shaiku_selection_put);
defsubr (&Shaiku_selection_owner_p);
defsubr (&Shaiku_drag_message);
+ defsubr (&Shaiku_roster_launch);
haiku_dnd_frame = NULL;
}
diff --git a/src/haikuterm.c b/src/haikuterm.c
index 341288133e8..802d7d2ac2f 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -43,17 +43,24 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
/* Minimum and maximum values used for Haiku scroll bars. */
#define BE_SB_MAX 12000000
-struct haiku_display_info *x_display_list = NULL;
-extern frame_parm_handler haiku_frame_parm_handlers[];
+/* The single Haiku display (if any). */
+struct haiku_display_info *x_display_list;
/* This is used to determine when to evict the font lookup cache,
which we do every 50 updates. */
static int up_to_date_count;
+/* List of defined fringe bitmaps. */
static void **fringe_bmps;
-static int max_fringe_bmp = 0;
+/* The amount of fringe bitmaps in that list. */
+static int max_fringe_bmp;
+
+/* Alist of resources to their values. */
static Lisp_Object rdb;
+
+/* Non-zero means that a HELP_EVENT has been generated since Emacs
+ start. */
static bool any_help_event_p;
char *
@@ -115,7 +122,8 @@ haiku_delete_terminal (struct terminal *terminal)
}
static const char *
-get_string_resource (void *ignored, const char *name, const char *class)
+haiku_get_string_resource (void *ignored, const char *name,
+ const char *class)
{
const char *native;
@@ -716,21 +724,40 @@ haiku_draw_relief_rect (struct glyph_string *s,
}
static void
+haiku_get_scale_factor (int *scale_x, int *scale_y)
+{
+ struct haiku_display_info *dpyinfo = x_display_list;
+
+ if (dpyinfo->resx > 96)
+ *scale_x = floor (dpyinfo->resx / 96);
+ if (dpyinfo->resy > 96)
+ *scale_y = floor (dpyinfo->resy / 96);
+}
+
+static void
haiku_draw_underwave (struct glyph_string *s, int width, int x)
{
- int wave_height = 3, wave_length = 2;
- int y, dx, dy, odd, xmax;
+ int wave_height, wave_length;
+ int y, dx, dy, odd, xmax, scale_x, scale_y;
float ax, ay, bx, by;
- void *view = FRAME_HAIKU_VIEW (s->f);
+ void *view;
+
+ scale_x = 1;
+ scale_y = 1;
+ haiku_get_scale_factor (&scale_x, &scale_y);
+ wave_height = 3 * scale_y;
+ wave_length = 2 * scale_x;
dx = wave_length;
dy = wave_height - 1;
y = s->ybase - wave_height + 3;
xmax = x + width;
+ view = FRAME_HAIKU_VIEW (s->f);
BView_StartClip (view);
haiku_clip_to_string (s);
BView_ClipToRect (view, x, y, width, wave_height);
+
ax = x - ((int) (x) % dx) + (float) 0.5;
bx = ax + dx;
odd = (int) (ax / dx) % 2;
@@ -741,6 +768,8 @@ haiku_draw_underwave (struct glyph_string *s, int width, int x)
else
by += dy;
+ BView_SetPenSize (view, scale_y);
+
while (ax <= xmax)
{
BView_StrokeLine (view, ax, ay, bx, by);
@@ -748,6 +777,8 @@ haiku_draw_underwave (struct glyph_string *s, int width, int x)
bx += dx, by = y + 0.5 + odd * dy;
odd = !odd;
}
+
+ BView_SetPenSize (view, 1);
BView_EndClip (view);
}
@@ -963,10 +994,11 @@ haiku_draw_string_box (struct glyph_string *s)
static void
haiku_draw_plain_background (struct glyph_string *s, struct face *face,
- int box_line_hwidth, int box_line_vwidth)
+ int x, int y, int width, int height)
{
void *view = FRAME_HAIKU_VIEW (s->f);
unsigned long cursor_color;
+
if (s->hl == DRAW_CURSOR)
{
haiku_merge_cursor_foreground (s, NULL, &cursor_color);
@@ -975,18 +1007,93 @@ haiku_draw_plain_background (struct glyph_string *s, struct face *face,
else
BView_SetHighColor (view, face->background_defaulted_p ?
FRAME_BACKGROUND_PIXEL (s->f) :
- face->background);
+ face->background);
+
+ BView_FillRectangle (view, x, y, width, height);
+}
+
+static struct haiku_bitmap_record *
+haiku_get_bitmap_rec (struct frame *f, ptrdiff_t id)
+{
+ return &FRAME_DISPLAY_INFO (f)->bitmaps[id - 1];
+}
+
+static void
+haiku_update_bitmap_rec (struct haiku_bitmap_record *rec,
+ uint32_t new_foreground,
+ uint32_t new_background)
+{
+ char *bits;
+ int x, y, bytes_per_line;
+
+ if (new_foreground == rec->stipple_foreground
+ && new_background == rec->stipple_background)
+ return;
+
+ bits = rec->stipple_bits;
+ bytes_per_line = (rec->width + 7) / 8;
+
+ for (y = 0; y < rec->height; y++)
+ {
+ for (x = 0; x < rec->width; x++)
+ haiku_put_pixel (rec->img, x, y,
+ ((bits[x / 8] >> (x % 8)) & 1
+ ? new_foreground : new_background));
+
+ bits += bytes_per_line;
+ }
- BView_FillRectangle (view, s->x,
- s->y + box_line_hwidth,
- s->background_width,
- s->height - 2 * box_line_hwidth);
+ rec->stipple_foreground = new_foreground;
+ rec->stipple_background = new_background;
}
static void
haiku_draw_stipple_background (struct glyph_string *s, struct face *face,
- int box_line_hwidth, int box_line_vwidth)
+ int x, int y, int width, int height,
+ bool explicit_colors_p,
+ uint32 explicit_background,
+ uint32 explicit_foreground)
{
+ struct haiku_bitmap_record *rec;
+ unsigned long foreground, background;
+ void *view;
+
+ view = FRAME_HAIKU_VIEW (s->f);
+ rec = haiku_get_bitmap_rec (s->f, s->face->stipple);
+
+ if (explicit_colors_p)
+ {
+ background = explicit_background;
+ foreground = explicit_foreground;
+ }
+ else if (s->hl == DRAW_CURSOR)
+ haiku_merge_cursor_foreground (s, &foreground, &background);
+ else
+ {
+ foreground = s->face->foreground;
+ background = s->face->background;
+ }
+
+ haiku_update_bitmap_rec (rec, foreground, background);
+
+ BView_StartClip (view);
+ haiku_clip_to_string (s);
+ BView_ClipToRect (view, x, y, width, height);
+ BView_DrawBitmapTiled (view, rec->img, 0, 0, -1, -1,
+ 0, 0, FRAME_PIXEL_WIDTH (s->f),
+ FRAME_PIXEL_HEIGHT (s->f));
+ BView_EndClip (view);
+}
+
+void
+haiku_draw_background_rect (struct glyph_string *s, struct face *face,
+ int x, int y, int width, int height)
+{
+ if (!s->stippled_p)
+ haiku_draw_plain_background (s, face, x, y, width, height);
+ else
+ haiku_draw_stipple_background (s, face, x, y, width, height,
+ false, 0, 0);
}
static void
@@ -1002,12 +1109,10 @@ haiku_maybe_draw_background (struct glyph_string *s, int force_p)
|| FONT_TOO_HIGH (s->font)
|| s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
{
- if (!face->stipple)
- haiku_draw_plain_background (s, face, box_line_width,
- box_vline_width);
- else
- haiku_draw_stipple_background (s, face, box_line_width,
- box_vline_width);
+ haiku_draw_background_rect (s, s->face, s->x, s->y + box_line_width,
+ s->background_width,
+ s->height - 2 * box_line_width);
+
s->background_filled_p = 1;
}
}
@@ -1182,9 +1287,8 @@ haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
static void
haiku_draw_stretch_glyph_string (struct glyph_string *s)
{
- eassert (s->first_glyph->type == STRETCH_GLYPH);
-
struct face *face = s->face;
+ uint32_t bkg;
if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p)
{
@@ -1232,9 +1336,11 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
int y = s->y;
int w = background_width - width, h = s->height;
+ /* Draw stipples manually because we want the background
+ part of a stretch glyph to have a stipple even if the
+ cursor is visible on top. */
if (!face->stipple)
{
- uint32_t bkg;
if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w))
haiku_mouse_face_colors (s, NULL, &bkg);
else
@@ -1243,6 +1349,16 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
BView_SetHighColor (view, bkg);
BView_FillRectangle (view, x, y, w, h);
}
+ else
+ {
+ if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w))
+ haiku_mouse_face_colors (s, NULL, &bkg);
+ else
+ bkg = face->background;
+
+ haiku_draw_stipple_background (s, s->face, x, y, w, h,
+ true, bkg, face->foreground);
+ }
}
}
else if (!s->background_filled_p)
@@ -1260,17 +1376,8 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
}
if (background_width > 0)
- {
- void *view = FRAME_HAIKU_VIEW (s->f);
- unsigned long bkg;
- if (s->hl == DRAW_CURSOR)
- haiku_merge_cursor_foreground (s, NULL, &bkg);
- else
- bkg = s->face->background;
-
- BView_SetHighColor (view, bkg);
- BView_FillRectangle (view, x, s->y, background_width, s->height);
- }
+ haiku_draw_background_rect (s, s->face, s->x, s->y,
+ background_width, s->height);
}
s->background_filled_p = 1;
}
@@ -1349,6 +1456,8 @@ haiku_draw_composite_glyph_string_foreground (struct glyph_string *s)
BView_SetHighColor (view, FRAME_OUTPUT_DATA (s->f)->cursor_fg);
else
BView_SetHighColor (view, s->face->foreground);
+
+ BView_SetPenSize (view, 1);
BView_StrokeRectangle (view, s->x, s->y,
s->width, s->height);
}
@@ -1538,6 +1647,7 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
void *view = FRAME_HAIKU_VIEW (s->f);
void *bitmap = s->img->pixmap;
+ /* TODO: implement stipples for images with masks. */
s->stippled_p = face->stipple != 0;
BView_SetHighColor (view, face->background);
@@ -1620,16 +1730,14 @@ haiku_draw_image_glyph_string (struct glyph_string *s)
static void
haiku_draw_glyph_string (struct glyph_string *s)
{
- void *view;
+ void *view = FRAME_HAIKU_VIEW (s->f);;
+ struct face *face = s->face;
block_input ();
- view = FRAME_HAIKU_VIEW (s->f);
BView_draw_lock (view, false, 0, 0, 0, 0);
prepare_face_for_display (s->f, s->face);
- struct face *face = s->face;
- if (face != s->face)
- prepare_face_for_display (s->f, face);
+ s->stippled_p = s->hl != DRAW_CURSOR && face->stipple;
if (s->next && s->right_overhang && !s->for_overlaps)
{
@@ -1641,13 +1749,16 @@ haiku_draw_glyph_string (struct glyph_string *s)
width += next->width, next = next->next)
if (next->first_glyph->type != IMAGE_GLYPH)
{
- prepare_face_for_display (s->f, s->next->face);
- haiku_start_clip (s->next);
- haiku_clip_to_string (s->next);
+ prepare_face_for_display (s->f, next->face);
+ next->stippled_p
+ = next->hl != DRAW_CURSOR && next->face->stipple;
+
+ haiku_start_clip (next);
+ haiku_clip_to_string (next);
if (next->first_glyph->type != STRETCH_GLYPH)
- haiku_maybe_draw_background (s->next, 1);
+ haiku_maybe_draw_background (next, true);
else
- haiku_draw_stretch_glyph_string (s->next);
+ haiku_draw_stretch_glyph_string (next);
haiku_end_clip (s);
}
}
@@ -1772,8 +1883,21 @@ haiku_draw_glyph_string (struct glyph_string *s)
}
}
}
+
haiku_end_clip (s);
BView_draw_unlock (view);
+
+ /* Set the stipple_p flag indicating whether or not a stipple was
+ drawn in s->row. That is the case either when s is a stretch
+ glyph string and s->face->stipple is not NULL, or when
+ s->face->stipple exists and s->hl is not DRAW_CURSOR, and s is
+ not an image. This is different from X. */
+ if (s->first_glyph->type != IMAGE_GLYPH
+ && s->face->stipple
+ && (s->first_glyph->type == STRETCH_GLYPH
+ || s->hl != DRAW_CURSOR))
+ s->row->stipple_p = true;
+
unblock_input ();
}
@@ -1809,8 +1933,9 @@ haiku_after_update_window_line (struct window *w,
void *view = FRAME_HAIKU_VIEW (f);
BView_draw_lock (view, false, 0, 0, 0, 0);
BView_StartClip (view);
- BView_SetHighColor (view, face->background_defaulted_p ?
- FRAME_BACKGROUND_PIXEL (f) : face->background);
+ BView_SetHighColor (view, (face->background_defaulted_p
+ ? FRAME_BACKGROUND_PIXEL (f)
+ : face->background));
BView_FillRectangle (view, 0, y, width, height);
BView_FillRectangle (view, FRAME_PIXEL_WIDTH (f) - width,
y, width, height);
@@ -2070,19 +2195,25 @@ haiku_draw_vertical_window_border (struct window *w,
static void
haiku_set_scroll_bar_default_width (struct frame *f)
{
- int unit = FRAME_COLUMN_WIDTH (f);
- FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = BScrollBar_default_size (0) + 1;
- FRAME_CONFIG_SCROLL_BAR_COLS (f) =
- (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit;
+ int unit, size;
+
+ unit = FRAME_COLUMN_WIDTH (f);
+ size = BScrollBar_default_size (0) + 1;
+
+ FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = size;
+ FRAME_CONFIG_SCROLL_BAR_COLS (f) = (size + unit - 1) / unit;
}
static void
haiku_set_scroll_bar_default_height (struct frame *f)
{
- int height = FRAME_LINE_HEIGHT (f);
- FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = BScrollBar_default_size (1) + 1;
- FRAME_CONFIG_SCROLL_BAR_LINES (f) =
- (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
+ int height, size;
+
+ height = FRAME_LINE_HEIGHT (f);
+ size = BScrollBar_default_size (true) + 1;
+
+ FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = size;
+ FRAME_CONFIG_SCROLL_BAR_LINES (f) = (size + height - 1) / height;
}
static void
@@ -2264,15 +2395,17 @@ static struct scroll_bar *
haiku_scroll_bar_create (struct window *w, int left, int top,
int width, int height, bool horizontal_p)
{
- struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct frame *f;
Lisp_Object barobj;
+ struct scroll_bar *bar;
+ void *scroll_bar;
+ void *view;
- void *sb = NULL;
- void *vw = FRAME_HAIKU_VIEW (f);
+ f = XFRAME (WINDOW_FRAME (w));
+ view = FRAME_HAIKU_VIEW (f);
block_input ();
- struct scroll_bar *bar
- = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
+ bar = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
XSETWINDOW (bar->window, w);
bar->top = top;
@@ -2285,15 +2418,14 @@ haiku_scroll_bar_create (struct window *w, int left, int top,
bar->update = -1;
bar->horizontal = horizontal_p;
- sb = BScrollBar_make_for_view (vw, horizontal_p,
- left, top, left + width - 1,
- top + height - 1, bar);
-
- BView_publish_scroll_bar (vw, left, top, width, height);
+ scroll_bar = BScrollBar_make_for_view (view, horizontal_p,
+ left, top, left + width - 1,
+ top + height - 1, bar);
+ BView_publish_scroll_bar (view, left, top, width, height);
bar->next = FRAME_SCROLL_BARS (f);
bar->prev = Qnil;
- bar->scroll_bar = sb;
+ bar->scroll_bar = scroll_bar;
XSETVECTOR (barobj, bar);
fset_scroll_bars (f, barobj);
@@ -2307,18 +2439,20 @@ haiku_scroll_bar_create (struct window *w, int left, int top,
static void
haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int position)
{
- eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
Lisp_Object barobj;
struct scroll_bar *bar;
int top, height, left, width;
int window_x, window_width;
+ void *view;
+ eassert (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w));
/* Get window dimensions. */
window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
left = window_x;
width = window_width;
top = WINDOW_SCROLL_BAR_AREA_Y (w);
height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
+ view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
block_input ();
@@ -2333,15 +2467,15 @@ haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int p
{
bar = XSCROLL_BAR (w->horizontal_scroll_bar);
- if (bar->left != left || bar->top != top ||
- bar->width != width || bar->height != height)
+ if (bar->left != left || bar->top != top
+ || bar->width != width || bar->height != height)
{
- void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
BView_forget_scroll_bar (view, bar->left, bar->top,
bar->width, bar->height);
BView_move_frame (bar->scroll_bar, left, top,
left + width - 1, top + height - 1);
BView_publish_scroll_bar (view, left, top, width, height);
+
bar->left = left;
bar->top = top;
bar->width = width;
@@ -2358,14 +2492,15 @@ haiku_set_horizontal_scroll_bar (struct window *w, int portion, int whole, int p
}
static void
-haiku_set_vertical_scroll_bar (struct window *w,
- int portion, int whole, int position)
+haiku_set_vertical_scroll_bar (struct window *w, int portion, int whole, int position)
{
- eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
Lisp_Object barobj;
struct scroll_bar *bar;
int top, height, left, width;
int window_y, window_height;
+ void *view;
+
+ eassert (WINDOW_HAS_VERTICAL_SCROLL_BAR (w));
/* Get window dimensions. */
window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
@@ -2375,8 +2510,10 @@ haiku_set_vertical_scroll_bar (struct window *w,
/* Compute the left edge and the width of the scroll bar area. */
left = WINDOW_SCROLL_BAR_AREA_X (w);
width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
- block_input ();
+ view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
+
+ block_input ();
if (NILP (w->vertical_scroll_bar))
{
bar = haiku_scroll_bar_create (w, left, top, width, height, false);
@@ -2387,15 +2524,15 @@ haiku_set_vertical_scroll_bar (struct window *w,
{
bar = XSCROLL_BAR (w->vertical_scroll_bar);
- if (bar->left != left || bar->top != top ||
- bar->width != width || bar->height != height)
+ if (bar->left != left || bar->top != top
+ || bar->width != width || bar->height != height)
{
- void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (w));
BView_forget_scroll_bar (view, bar->left, bar->top,
bar->width, bar->height);
BView_move_frame (bar->scroll_bar, left, top,
left + width - 1, top + height - 1);
BView_publish_scroll_bar (view, left, top, width, height);
+
bar->left = left;
bar->top = top;
bar->width = width;
@@ -2416,25 +2553,52 @@ static void
haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
struct draw_fringe_bitmap_params *p)
{
- void *view = FRAME_HAIKU_VIEW (XFRAME (WINDOW_FRAME (w)));
- struct face *face = p->face;
+ struct face *face;
+ struct frame *f;
+ struct haiku_bitmap_record *rec;
+ void *view, *bitmap;
+ uint32 col;
+
+ f = XFRAME (WINDOW_FRAME (w));
+ view = FRAME_HAIKU_VIEW (f);
+ face = p->face;
block_input ();
BView_draw_lock (view, true, p->x, p->y, p->wd, p->h);
BView_StartClip (view);
haiku_clip_to_row (w, row, ANY_AREA);
+
if (p->bx >= 0 && !p->overlay_p)
{
- BView_SetHighColor (view, face->background);
- BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny);
+ if (!face->stipple)
+ {
+ BView_SetHighColor (view, face->background);
+ BView_FillRectangle (view, p->bx, p->by, p->nx, p->ny);
+ }
+ else
+ {
+ rec = haiku_get_bitmap_rec (f, face->stipple);
+ haiku_update_bitmap_rec (rec, face->foreground,
+ face->background);
+
+ BView_StartClip (view);
+ haiku_clip_to_row (w, row, ANY_AREA);
+ BView_ClipToRect (view, p->bx, p->by, p->nx, p->ny);
+ BView_DrawBitmapTiled (view, rec->img, 0, 0, -1, -1,
+ 0, 0, FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f));
+ BView_EndClip (view);
+
+ row->stipple_p = true;
+ }
}
if (p->which
&& p->which < max_fringe_bmp
&& p->which < max_used_fringe_bitmap)
{
- void *bitmap = fringe_bmps[p->which];
+ bitmap = fringe_bmps[p->which];
if (!bitmap)
{
@@ -2448,8 +2612,6 @@ haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
bitmap = fringe_bmps[p->which];
}
- uint32_t col;
-
if (!p->cursor_p)
col = face->foreground;
else if (p->overlay_p)
@@ -3871,7 +4033,7 @@ haiku_create_terminal (struct haiku_display_info *dpyinfo)
terminal->frame_visible_invisible_hook = haiku_set_frame_visible_invisible;
terminal->set_frame_offset_hook = haiku_set_offset;
terminal->delete_terminal_hook = haiku_delete_terminal;
- terminal->get_string_resource_hook = get_string_resource;
+ terminal->get_string_resource_hook = haiku_get_string_resource;
terminal->set_new_font_hook = haiku_new_font;
terminal->defined_color_hook = haiku_defined_color;
terminal->set_window_size_hook = haiku_set_window_size;
@@ -3937,9 +4099,9 @@ haiku_term_init (void)
dpyinfo->display = BApplication_setup ();
dpyinfo->next = x_display_list;
dpyinfo->n_planes = be_get_display_planes ();
- x_display_list = dpyinfo;
+ be_get_display_resolution (&dpyinfo->resx, &dpyinfo->resy);
- BScreen_res (&dpyinfo->resx, &dpyinfo->resy);
+ x_display_list = dpyinfo;
terminal = haiku_create_terminal (dpyinfo);
if (current_kboard == initial_kboard)
@@ -4080,9 +4242,15 @@ mark_haiku_display (void)
void
haiku_scroll_bar_remove (struct scroll_bar *bar)
{
+ void *view;
+ struct frame *f;
+
+ f = WINDOW_XFRAME (XWINDOW (bar->window));
+ view = FRAME_HAIKU_VIEW (f);
+
block_input ();
- void *view = FRAME_HAIKU_VIEW (WINDOW_XFRAME (XWINDOW (bar->window)));
- BView_forget_scroll_bar (view, bar->left, bar->top, bar->width, bar->height);
+ BView_forget_scroll_bar (view, bar->left, bar->top,
+ bar->width, bar->height);
BScrollBar_delete (bar->scroll_bar);
expose_frame (WINDOW_XFRAME (XWINDOW (bar->window)),
bar->left, bar->top, bar->width, bar->height);
@@ -4091,7 +4259,6 @@ haiku_scroll_bar_remove (struct scroll_bar *bar)
wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
else
wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
-
unblock_input ();
};
diff --git a/src/haikuterm.h b/src/haikuterm.h
index 30b474b1e1d..cc032d03892 100644
--- a/src/haikuterm.h
+++ b/src/haikuterm.h
@@ -52,6 +52,10 @@ struct haiku_bitmap_record
char *file;
int refcount;
int height, width, depth;
+
+ uint32_t stipple_foreground;
+ uint32_t stipple_background;
+ void *stipple_bits;
};
struct haiku_display_info
@@ -205,6 +209,8 @@ extern struct font_driver const haikufont_driver;
extern Lisp_Object tip_frame;
extern struct frame *haiku_dnd_frame;
+extern frame_parm_handler haiku_frame_parm_handlers[];
+
struct scroll_bar
{
/* These fields are shared by all vectors. */
@@ -323,6 +329,9 @@ extern int haiku_load_image (struct frame *, struct image *,
extern void syms_of_haikuimage (void);
#endif
+extern void haiku_draw_background_rect (struct glyph_string *, struct face *,
+ int, int, int, int);
+
#ifdef USE_BE_CAIRO
extern cairo_t *haiku_begin_cr_clip (struct frame *, struct glyph_string *);
diff --git a/src/image.c b/src/image.c
index e4b56e29cff..0c14173d833 100644
--- a/src/image.c
+++ b/src/image.c
@@ -542,12 +542,26 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
#endif /* HAVE_PGTK */
#ifdef HAVE_HAIKU
- void *bitmap = BBitmap_new (width, height, 1);
+ void *bitmap, *stipple;
+ int bytes_per_line, x, y;
+
+ bitmap = BBitmap_new (width, height, false);
if (!bitmap)
return -1;
- BBitmap_import_mono_bits (bitmap, bits, width, height);
+ bytes_per_line = (width + 7) / 8;
+ stipple = xmalloc (height * bytes_per_line);
+ memcpy (stipple, bits, height * bytes_per_line);
+
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ PUT_PIXEL (bitmap, x, y, ((bits[8] >> (x % 8)) & 1
+ ? f->foreground_pixel
+ : f->background_pixel));
+ bits += bytes_per_line;
+ }
#endif
id = image_allocate_bitmap_record (f);
@@ -567,6 +581,11 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
#ifdef HAVE_HAIKU
dpyinfo->bitmaps[id - 1].img = bitmap;
dpyinfo->bitmaps[id - 1].depth = 1;
+ dpyinfo->bitmaps[id - 1].stipple_bits = stipple;
+ dpyinfo->bitmaps[id - 1].stipple_foreground
+ = f->foreground_pixel & 0xffffffff;
+ dpyinfo->bitmaps[id - 1].stipple_background
+ = f->background_pixel & 0xffffffff;
#endif
dpyinfo->bitmaps[id - 1].file = NULL;
@@ -592,24 +611,55 @@ image_create_bitmap_from_data (struct frame *f, char *bits,
return id;
}
+#if defined HAVE_HAIKU || defined HAVE_NS
+static char *slurp_file (int, ptrdiff_t *);
+static Lisp_Object image_find_image_fd (Lisp_Object, int *);
+static bool xbm_read_bitmap_data (struct frame *, char *, char *,
+ int *, int *, char **, bool);
+#endif
+
/* Create bitmap from file FILE for frame F. */
ptrdiff_t
image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
{
-#if defined (HAVE_NTGUI) || defined (HAVE_HAIKU)
+#if defined (HAVE_NTGUI)
return -1; /* W32_TODO : bitmap support */
#else
Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
#endif
#ifdef HAVE_NS
- ptrdiff_t id;
- void *bitmap = ns_image_from_file (file);
+ ptrdiff_t id, size;
+ int fd, width, height, rc;
+ char *contents, *data;
+ void *bitmap;
- if (!bitmap)
+ if (!STRINGP (image_find_image_fd (file, &fd)))
+ return -1;
+
+ contents = slurp_file (fd, &size);
+
+ if (!contents)
+ return -1;
+
+ rc = xbm_read_bitmap_data (f, contents, contents + size,
+ &width, &height, &data, 0);
+
+ if (!rc)
+ {
+ xfree (contents);
return -1;
+ }
+ bitmap = ns_image_from_XBM (data, width, height, 0, 0);
+
+ if (!bitmap)
+ {
+ xfree (contents);
+ xfree (data);
+ return -1;
+ }
id = image_allocate_bitmap_record (f);
dpyinfo->bitmaps[id - 1].img = bitmap;
@@ -618,6 +668,9 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
dpyinfo->bitmaps[id - 1].depth = 1;
dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
+
+ xfree (contents);
+ xfree (data);
return id;
#endif
@@ -637,7 +690,6 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
dpyinfo->bitmaps[id - 1].img = bitmap;
dpyinfo->bitmaps[id - 1].refcount = 1;
dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
- //dpyinfo->bitmaps[id - 1].depth = 1;
dpyinfo->bitmaps[id - 1].height = gdk_pixbuf_get_width (bitmap);
dpyinfo->bitmaps[id - 1].width = gdk_pixbuf_get_height (bitmap);
dpyinfo->bitmaps[id - 1].pattern
@@ -692,6 +744,69 @@ image_create_bitmap_from_file (struct frame *f, Lisp_Object file)
return id;
#endif /* HAVE_X_WINDOWS */
+
+#ifdef HAVE_HAIKU
+ ptrdiff_t id, size;
+ int fd, width, height, rc, bytes_per_line, x, y;
+ char *contents, *data, *tmp;
+ void *bitmap;
+
+ if (!STRINGP (image_find_image_fd (file, &fd)))
+ return -1;
+
+ contents = slurp_file (fd, &size);
+
+ if (!contents)
+ return -1;
+
+ rc = xbm_read_bitmap_data (f, contents, contents + size,
+ &width, &height, &data, 0);
+
+ if (!rc)
+ {
+ xfree (contents);
+ return -1;
+ }
+
+ bitmap = BBitmap_new (width, height, false);
+
+ if (!bitmap)
+ {
+ xfree (contents);
+ xfree (data);
+ return -1;
+ }
+
+ id = image_allocate_bitmap_record (f);
+
+ dpyinfo->bitmaps[id - 1].img = bitmap;
+ dpyinfo->bitmaps[id - 1].depth = 1;
+ dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
+ dpyinfo->bitmaps[id - 1].height = height;
+ dpyinfo->bitmaps[id - 1].width = width;
+ dpyinfo->bitmaps[id - 1].refcount = 1;
+ dpyinfo->bitmaps[id - 1].stipple_foreground
+ = f->foreground_pixel & 0xffffffff;
+ dpyinfo->bitmaps[id - 1].stipple_background
+ = f->background_pixel & 0xffffffff;
+ dpyinfo->bitmaps[id - 1].stipple_bits = data;
+
+ bytes_per_line = (width + 7) / 8;
+ tmp = data;
+
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ PUT_PIXEL (bitmap, x, y, ((tmp[x / 8] >> (x % 8)) & 1
+ ? f->foreground_pixel
+ : f->background_pixel));
+
+ tmp += bytes_per_line;
+ }
+
+ xfree (contents);
+ return id;
+#endif
}
/* Free bitmap B. */
@@ -724,6 +839,9 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
#ifdef HAVE_HAIKU
BBitmap_free (bm->img);
+
+ if (bm->stipple_bits)
+ xfree (bm->stipple_bits);
#endif
if (bm->file)
diff --git a/src/keyboard.c b/src/keyboard.c
index 70908120cb0..e8f51f8a6fe 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -95,8 +95,6 @@ volatile int interrupt_input_blocked;
The maybe_quit function checks this. */
volatile bool pending_signals;
-enum { KBD_BUFFER_SIZE = 4096 };
-
KBOARD *initial_kboard;
KBOARD *current_kboard;
static KBOARD *all_kboards;
@@ -290,14 +288,14 @@ bool input_was_pending;
/* Circular buffer for pre-read keyboard input. */
-static union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
+union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
/* Pointer to next available character in kbd_buffer.
If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty. */
-static union buffered_input_event *kbd_fetch_ptr;
+union buffered_input_event *kbd_fetch_ptr;
/* Pointer to next place to store character in kbd_buffer. */
-static union buffered_input_event *kbd_store_ptr;
+union buffered_input_event *kbd_store_ptr;
/* The above pair of variables forms a "queue empty" flag. When we
enqueue a non-hook event, we increment kbd_store_ptr. When we
@@ -4022,6 +4020,11 @@ kbd_buffer_get_event (KBOARD **kbp,
kbd_fetch_ptr = next_kbd_event (event);
input_pending = readable_events (0);
+ /* This means this event was already handled in
+ `x_dnd_begin_drag_and_drop'. */
+ if (event->ie.modifiers < x_dnd_unsupported_event_level)
+ break;
+
f = XFRAME (event->ie.frame_or_window);
if (!FRAME_LIVE_P (f))
@@ -4029,11 +4032,12 @@ kbd_buffer_get_event (KBOARD **kbp,
if (!NILP (Vx_dnd_unsupported_drop_function))
{
- if (!NILP (call6 (Vx_dnd_unsupported_drop_function,
+ if (!NILP (call7 (Vx_dnd_unsupported_drop_function,
XCAR (XCDR (event->ie.arg)), event->ie.x,
event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
make_uint (event->ie.code),
- event->ie.frame_or_window)))
+ event->ie.frame_or_window,
+ make_int (event->ie.timestamp))))
break;
}
diff --git a/src/keyboard.h b/src/keyboard.h
index cd5f677b963..a0b7204fa2b 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -358,6 +358,11 @@ enum menu_item_idx
MENU_ITEMS_ITEM_LENGTH
};
+enum
+ {
+ KBD_BUFFER_SIZE = 4096
+ };
+
extern void unuse_menu_items (void);
/* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU
@@ -419,6 +424,10 @@ extern void unuse_menu_items (void);
happens. */
extern struct timespec *input_available_clear_time;
+extern union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
+extern union buffered_input_event *kbd_fetch_ptr;
+extern union buffered_input_event *kbd_store_ptr;
+
extern bool ignore_mouse_drag_p;
extern Lisp_Object parse_modifiers (Lisp_Object);
diff --git a/src/nsmenu.m b/src/nsmenu.m
index b0ab12bb87d..34864f94087 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -741,15 +741,15 @@ prettify_key (const char *key)
/* p = [view convertPoint:p fromView: nil]; */
p.y = NSHeight ([view frame]) - p.y;
e = [[view window] currentEvent];
- event = [NSEvent mouseEventWithType: NSEventTypeRightMouseDown
- location: p
- modifierFlags: 0
- timestamp: [e timestamp]
- windowNumber: [[view window] windowNumber]
- context: nil
- eventNumber: 0 /* [e eventNumber] */
- clickCount: 1
- pressure: 0];
+ event = [NSEvent mouseEventWithType: NSEventTypeRightMouseDown
+ location: p
+ modifierFlags: 0
+ timestamp: [e timestamp]
+ windowNumber: [[view window] windowNumber]
+ context: nil
+ eventNumber: 0 /* [e eventNumber] */
+ clickCount: 1
+ pressure: 0];
context_menu_value = -1;
[NSMenu popUpContextMenu: self withEvent: event forView: view];
@@ -767,6 +767,10 @@ prettify_key (const char *key)
Lisp_Object vec = f->menu_bar_vector;
Lisp_Object help, frame;
+ /* This isn't a menubar, ignore. */
+ if (context_menu_value == -1)
+ return;
+
if (idx >= ASIZE (vec))
return;
diff --git a/src/nsterm.m b/src/nsterm.m
index fef7f0dc6c8..82062033335 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -3079,7 +3079,9 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
break;
case HOLLOW_BOX_CURSOR:
draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT);
- [NSBezierPath strokeRect: r];
+
+ /* This works like it does in PostScript, not X Windows. */
+ [NSBezierPath strokeRect: NSInsetRect (r, 0.5, 0.5)];
break;
case HBAR_CURSOR:
NSRectFill (r);
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index c8c8bd0d85e..4d6221d8034 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -1333,9 +1333,7 @@ pgtk_draw_glyph_string_background (struct glyph_string *s, bool force_p)
if (s->stippled_p)
{
/* Fill background with a stipple pattern. */
-
- fill_background (s,
- s->x, s->y + box_line_width,
+ fill_background (s, s->x, s->y + box_line_width,
s->background_width,
s->height - 2 * box_line_width);
s->background_filled_p = true;
@@ -2501,9 +2499,7 @@ pgtk_draw_glyph_string (struct glyph_string *s)
if (s->face->underline_defaulted_p)
pgtk_draw_underwave (s, s->xgcv.foreground);
else
- {
- pgtk_draw_underwave (s, s->face->underline_color);
- }
+ pgtk_draw_underwave (s, s->face->underline_color);
}
else if (s->face->underline == FACE_UNDER_LINE)
{
@@ -2670,6 +2666,11 @@ pgtk_draw_glyph_string (struct glyph_string *s)
}
}
+ /* TODO: figure out in which cases the stipple is actually drawn on
+ PGTK. */
+ if (!s->row->stipple_p)
+ s->row->stipple_p = s->face->stipple;
+
/* Reset clipping. */
pgtk_end_cr_clip (s->f);
s->num_clips = 0;
@@ -3505,9 +3506,7 @@ pgtk_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
mono-displays, the fill style may have been changed to
FillSolid in pgtk_draw_glyph_string_background. */
if (face->stipple)
- {
- fill_background_by_face (f, face, p->bx, p->by, p->nx, p->ny);
- }
+ fill_background_by_face (f, face, p->bx, p->by, p->nx, p->ny);
else
{
pgtk_set_cr_source_with_color (f, face->background, true);
@@ -6608,9 +6607,9 @@ pgtk_xlfd_to_fontname (const char *xlfd)
}
bool
-pgtk_defined_color (struct frame *f,
- const char *name,
- Emacs_Color * color_def, bool alloc, bool makeIndex)
+pgtk_defined_color (struct frame *f, const char *name,
+ Emacs_Color *color_def, bool alloc,
+ bool makeIndex)
/* --------------------------------------------------------------------------
Return true if named color found, and set color_def rgb accordingly.
If makeIndex and alloc are nonzero put the color in the color_table,
diff --git a/src/process.c b/src/process.c
index 08a02ad9423..2f8863aef25 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1071,13 +1071,24 @@ record_deleted_pid (pid_t pid, Lisp_Object filename)
}
-DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
+DEFUN ("delete-process", Fdelete_process, Sdelete_process, 0, 1,
+ "(list 'message)",
doc: /* Delete PROCESS: kill it and forget about it immediately.
PROCESS may be a process, a buffer, the name of a process or buffer, or
-nil, indicating the current buffer's process. */)
+nil, indicating the current buffer's process.
+
+Interactively, it will kill the current buffer's process. */)
(register Lisp_Object process)
{
register struct Lisp_Process *p;
+ bool mess = false;
+
+ /* We use this to see whether we were called interactively. */
+ if (EQ (process, Qmessage))
+ {
+ mess = true;
+ process = Qnil;
+ }
process = get_process (process);
p = XPROCESS (process);
@@ -1131,6 +1142,8 @@ nil, indicating the current buffer's process. */)
}
}
remove_process (process);
+ if (mess)
+ message ("Deleted process");
return Qnil;
}
@@ -8637,6 +8650,7 @@ sentinel or a process filter function has an error. */);
DEFSYM (Qnull, "null");
DEFSYM (Qpipe_process_p, "pipe-process-p");
+ DEFSYM (Qmessage, "message");
defsubr (&Sprocessp);
defsubr (&Sget_process);
diff --git a/src/termhooks.h b/src/termhooks.h
index 8c193914ba8..08bde0aec0d 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -223,6 +223,11 @@ enum event_kind
gives the timestamp where the drop
happened.
+ .modifiers gives a number that
+ determines if an event was already
+ handled by
+ `x_dnd_begin_drag_and_drop'.
+
.x and .y give the coordinates of
the drop originating from the root
window. */
diff --git a/src/w32fns.c b/src/w32fns.c
index 0f25c1a594a..e5becb5d64f 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -247,6 +247,8 @@ static HWND w32_visible_system_caret_hwnd;
static int w32_unicode_gui;
+static bool w32_selection_dialog_open;
+
/* From w32menu.c */
int menubar_in_use = 0;
@@ -4184,6 +4186,16 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
update_rect.left, update_rect.top,
update_rect.right, update_rect.bottom));
#endif
+ /* Under double-buffering, update the frame from the back
+ buffer, to prevent a "ghost" of the selection dialog to
+ be left on display while the user selects in the dialog. */
+ if (w32_selection_dialog_open
+ && !w32_disable_double_buffering
+ && FRAME_OUTPUT_DATA (f)->paint_dc)
+ BitBlt (FRAME_OUTPUT_DATA (f)->paint_buffer_handle,
+ 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f),
+ FRAME_OUTPUT_DATA (f)->paint_dc, 0, 0, SRCCOPY);
+
EndPaint (hwnd, &paintStruct);
leave_crit ();
@@ -7755,6 +7767,15 @@ w32_dialog_in_progress (Lisp_Object in_progress)
{
Lisp_Object frames, frame;
+ /* Indicate to w32_wnd_proc that the selection dialog is about to be
+ open (or was closed, if IN_PROGRESS is nil). */
+ if (!w32_disable_double_buffering)
+ {
+ enter_crit ();
+ w32_selection_dialog_open = !NILP (in_progress);
+ leave_crit ();
+ }
+
/* Don't let frames in `above' z-group obscure dialog windows. */
FOR_EACH_FRAME (frames, frame)
{
diff --git a/src/w32notify.c b/src/w32notify.c
index e7d2f0f076b..ccefecb6596 100644
--- a/src/w32notify.c
+++ b/src/w32notify.c
@@ -40,8 +40,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
and returns. That causes the WaitForSingleObjectEx function call
inside watch_worker to return, but the thread won't terminate until
the event telling to do so will be signaled. The completion
- routine issued another call to ReadDirectoryChangesW as quickly as
- possible. (Except when it does not, see below.)
+ routine then issues another call to ReadDirectoryChangesW as quickly
+ as possible. (Except when it does not, see below.)
In a GUI session, the WM_EMACS_FILENOTIFY message posted to the
message queue gets dispatched to the main Emacs window procedure,
diff --git a/src/window.c b/src/window.c
index 6d28384eeb7..47c008a643a 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1868,7 +1868,13 @@ point not visible in the window.
For reliable setting of WINDOW start position, make sure point is
at a position that will be visible when that start is in effect,
otherwise there's a chance POS will be disregarded, e.g., if point
-winds up in a partially-visible line. */)
+winds up in a partially-visible line.
+
+The setting of the WINDOW's start position takes effect during the
+next redisplay cycle, not immediately. If NOFORCE is nil or
+omitted, forcing the display of WINDOW to start at POS cancels
+any setting of WINDOW's vertical scroll (\"vscroll\") amount
+set by `set-window-vscroll' and by scrolling functions. */)
(Lisp_Object window, Lisp_Object pos, Lisp_Object noforce)
{
register struct window *w = decode_live_window (window);
@@ -5630,7 +5636,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
if (w->vscroll < 0 && rtop > 0)
{
px = max (0, -w->vscroll - min (rtop, -dy));
- Fset_window_vscroll (window, make_fixnum (px), Qt);
+ Fset_window_vscroll (window, make_fixnum (px), Qt,
+ Qnil);
return;
}
}
@@ -5640,7 +5647,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
if (rbot > 0 && (w->vscroll < 0 || vpos == 0))
{
px = max (0, -w->vscroll + min (rbot, dy));
- Fset_window_vscroll (window, make_fixnum (px), Qt);
+ Fset_window_vscroll (window, make_fixnum (px), Qt,
+ Qnil);
return;
}
@@ -5649,7 +5657,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
{
ptrdiff_t spos;
- Fset_window_vscroll (window, make_fixnum (0), Qt);
+ Fset_window_vscroll (window, make_fixnum (0), Qt,
+ Qnil);
/* If there are other text lines above the current row,
move window start to current row. Else to next row. */
if (rbot > 0)
@@ -5668,7 +5677,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
}
}
/* Cancel previous vscroll. */
- Fset_window_vscroll (window, make_fixnum (0), Qt);
+ Fset_window_vscroll (window, make_fixnum (0), Qt, Qnil);
}
itdata = bidi_shelve_cache ();
@@ -7938,7 +7947,7 @@ optional second arg PIXELS-P means value is measured in pixels. */)
DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
- 2, 3, 0,
+ 2, 4, 0,
doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
This takes effect when displaying tall lines or images.
@@ -7948,8 +7957,12 @@ optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
If PIXELS-P is nil, VSCROLL may have to be rounded so that it
corresponds to an integral number of pixels. The return value is the
result of this rounding.
-If PIXELS-P is non-nil, the return value is VSCROLL. */)
- (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p)
+If PIXELS-P is non-nil, the return value is VSCROLL.
+
+PRESERVE_VSCROLL_P makes setting the start of WINDOW preserve the
+vscroll if its start is "frozen" due to a resized mini-window. */)
+ (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p,
+ Lisp_Object preserve_vscroll_p)
{
struct window *w = decode_live_window (window);
struct frame *f = XFRAME (w->frame);
@@ -7974,7 +7987,12 @@ If PIXELS-P is non-nil, the return value is VSCROLL. */)
/* Prevent redisplay shortcuts. */
XBUFFER (w->contents)->prevent_redisplay_optimizations_p = true;
+
+ /* Mark W for redisplay. (bug#55299) */
+ wset_redisplay (w);
}
+
+ w->preserve_vscroll_p = !NILP (preserve_vscroll_p);
}
return Fwindow_vscroll (window, pixels_p);
diff --git a/src/window.h b/src/window.h
index 387a3be36a9..7f7de588463 100644
--- a/src/window.h
+++ b/src/window.h
@@ -445,6 +445,10 @@ struct window
window. */
bool_bf suspend_auto_hscroll : 1;
+ /* True if vscroll should be preserved while forcing the start due
+ to a frozen window. */
+ bool_bf preserve_vscroll_p : 1;
+
/* Amount by which lines of this window are scrolled in
y-direction (smooth scrolling). */
int vscroll;
diff --git a/src/xdisp.c b/src/xdisp.c
index 50efa50c55b..82a018485d3 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -17006,6 +17006,7 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p)
w->window_end_valid = true;
w->update_mode_line = false;
+ w->preserve_vscroll_p = false;
}
w->redisplay = !accurate_p;
@@ -19168,7 +19169,14 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
int new_vpos = -1;
w->force_start = false;
- w->vscroll = 0;
+
+ /* The vscroll should be preserved in this case, since
+ `pixel-scroll-precision-mode' must continue working normally
+ when a mini-window is resized. (bug#55312) */
+ if (!w->preserve_vscroll_p || !window_frozen_p (w))
+ w->vscroll = 0;
+
+ w->preserve_vscroll_p = false;
w->window_end_valid = false;
/* Forget any recorded base line for line number display. */
@@ -32015,14 +32023,16 @@ gui_insert_glyphs (struct window *w, struct glyph_row *updated_row,
void
gui_clear_end_of_line (struct window *w, struct glyph_row *updated_row,
- enum glyph_row_area updated_area, int to_x)
+ enum glyph_row_area updated_area, int to_x)
{
struct frame *f;
int max_x, min_y, max_y;
int from_x, from_y, to_y;
+ struct face *face;
eassert (updated_row);
f = XFRAME (w->frame);
+ face = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID);
if (updated_row->full_width_p)
max_x = (WINDOW_PIXEL_WIDTH (w)
@@ -32074,6 +32084,9 @@ gui_clear_end_of_line (struct window *w, struct glyph_row *updated_row,
block_input ();
FRAME_RIF (f)->clear_frame_area (f, from_x, from_y,
to_x - from_x, to_y - from_y);
+
+ if (face && !updated_row->stipple_p)
+ updated_row->stipple_p = face->stipple;
unblock_input ();
}
}
diff --git a/src/xfns.c b/src/xfns.c
index dc8f02780ce..7dbf1e16c3a 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -2372,6 +2372,63 @@ x_set_scroll_bar_default_height (struct frame *f)
#endif
}
+static void
+x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+ double alpha = 1.0;
+ double newval[2];
+ int i;
+ Lisp_Object item;
+ bool alpha_identical_p;
+
+ alpha_identical_p = true;
+
+ for (i = 0; i < 2; i++)
+ {
+ newval[i] = 1.0;
+ if (CONSP (arg))
+ {
+ item = CAR (arg);
+ arg = CDR (arg);
+
+ alpha_identical_p = false;
+ }
+ else
+ item = arg;
+
+ if (NILP (item))
+ alpha = - 1.0;
+ else if (FLOATP (item))
+ {
+ alpha = XFLOAT_DATA (item);
+ if (! (0 <= alpha && alpha <= 1.0))
+ args_out_of_range (make_float (0.0), make_float (1.0));
+ }
+ else if (FIXNUMP (item))
+ {
+ EMACS_INT ialpha = XFIXNUM (item);
+ if (! (0 <= ialpha && ialpha <= 100))
+ args_out_of_range (make_fixnum (0), make_fixnum (100));
+ alpha = ialpha / 100.0;
+ }
+ else
+ wrong_type_argument (Qnumberp, item);
+ newval[i] = alpha;
+ }
+
+ for (i = 0; i < 2; i++)
+ f->alpha[i] = newval[i];
+
+ FRAME_X_OUTPUT (f)->alpha_identical_p = alpha_identical_p;
+
+ if (FRAME_TERMINAL (f)->set_frame_alpha_hook)
+ {
+ block_input ();
+ FRAME_TERMINAL (f)->set_frame_alpha_hook (f);
+ unblock_input ();
+ }
+}
+
/* Record in frame F the specified or default value according to ALIST
of the parameter named PROP (a Lisp symbol). If no value is
@@ -9368,7 +9425,7 @@ frame_parm_handler x_frame_parm_handlers[] =
x_set_wait_for_wm,
gui_set_fullscreen,
gui_set_font_backend,
- gui_set_alpha,
+ x_set_alpha,
x_set_sticky,
x_set_tool_bar_position,
#ifdef HAVE_XDBE
diff --git a/src/xmenu.c b/src/xmenu.c
index 418628d4916..aaf53569a72 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -677,7 +677,10 @@ x_activate_menubar (struct frame *f)
}
}
#endif
- XtDispatchEvent (f->output_data.x->saved_menu_event);
+ /* The cascade button might have been deleted, so don't activate the
+ popup if it no widget was found to dispatch to. */
+ popup_activated_flag
+ = XtDispatchEvent (f->output_data.x->saved_menu_event);
#endif
unblock_input ();
@@ -1618,6 +1621,84 @@ popup_selection_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
menu_item_selection = client_data;
}
+
+#ifdef HAVE_XINPUT2
+static void
+prepare_for_entry_into_toolkit_menu (struct frame *f)
+{
+ XIEventMask mask;
+ ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
+ unsigned char *m;
+ Lisp_Object tail, frame;
+ struct x_display_info *dpyinfo;
+
+ dpyinfo = FRAME_DISPLAY_INFO (f);
+
+ if (!dpyinfo->supports_xi2)
+ return;
+
+ mask.mask = m = alloca (l);
+ memset (m, 0, l);
+ mask.mask_len = l;
+
+ mask.deviceid = XIAllMasterDevices;
+
+ XISetMask (m, XI_Motion);
+ XISetMask (m, XI_Enter);
+ XISetMask (m, XI_Leave);
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ f = XFRAME (frame);
+
+ if (FRAME_X_P (f)
+ && FRAME_DISPLAY_INFO (f) == dpyinfo
+ && !FRAME_TOOLTIP_P (f))
+ XISelectEvents (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ &mask, 1);
+ }
+}
+
+static void
+leave_toolkit_menu (void *data)
+{
+ XIEventMask mask;
+ ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
+ unsigned char *m;
+ Lisp_Object tail, frame;
+ struct x_display_info *dpyinfo;
+ struct frame *f;
+
+ dpyinfo = FRAME_DISPLAY_INFO ((struct frame *) data);
+
+ if (!dpyinfo->supports_xi2)
+ return;
+
+ mask.mask = m = alloca (l);
+ memset (m, 0, l);
+ mask.mask_len = l;
+
+ mask.deviceid = XIAllMasterDevices;
+
+ XISetMask (m, XI_ButtonPress);
+ XISetMask (m, XI_ButtonRelease);
+ XISetMask (m, XI_Motion);
+ XISetMask (m, XI_Enter);
+ XISetMask (m, XI_Leave);
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ f = XFRAME (frame);
+
+ if (FRAME_X_P (f)
+ && FRAME_DISPLAY_INFO (f) == dpyinfo
+ && !FRAME_TOOLTIP_P (f))
+ XISelectEvents (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ &mask, 1);
+ }
+}
+#endif
+
/* ID is the LWLIB ID of the dialog box. */
static void
@@ -1720,11 +1801,9 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
#ifdef HAVE_XINPUT2
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
- bool any_xi_grab_p = false;
/* Clear the XI2 grab, and if any XI2 grab was set, place a core
grab on the frame's edit widget. */
-
if (dpyinfo->supports_xi2)
XGrabServer (dpyinfo->display);
@@ -1735,7 +1814,6 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
{
if (dpyinfo->devices[i].grab)
{
- any_xi_grab_p = true;
dpyinfo->devices[i].grab = 0;
XIUngrabDevice (dpyinfo->display,
@@ -1745,20 +1823,6 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
}
}
- if (any_xi_grab_p)
- {
-#ifndef USE_MOTIF
- XGrabPointer (dpyinfo->display,
- FRAME_X_WINDOW (f),
- False, (PointerMotionMask
- | PointerMotionHintMask
- | ButtonReleaseMask
- | ButtonPressMask),
- GrabModeSync, GrabModeAsync,
- None, None, CurrentTime);
-#endif
- }
-
#ifdef USE_MOTIF
if (dpyinfo->supports_xi2)
{
@@ -1781,6 +1845,14 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
#endif
#endif
+#ifdef HAVE_XINPUT2
+ prepare_for_entry_into_toolkit_menu (f);
+
+#ifdef USE_LUCID
+ if (dpyinfo->supports_xi2)
+ x_mouse_leave (dpyinfo);
+#endif
+#endif
/* Display the menu. */
lw_popup_menu (menu, &dummy);
@@ -1791,17 +1863,15 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
popup_activated_flag = 1;
-#if defined HAVE_XINPUT2 && !defined USE_MOTIF
- if (any_xi_grab_p)
- XAllowEvents (dpyinfo->display, AsyncPointer, CurrentTime);
-#endif
-
x_activate_timeout_atimer ();
{
specpdl_ref specpdl_count = SPECPDL_INDEX ();
record_unwind_protect_int (pop_down_menu, (int) menu_id);
+#ifdef HAVE_XINPUT2
+ record_unwind_protect_ptr (leave_toolkit_menu, f);
+#endif
/* Process events that apply to the menu. */
popup_get_selection (0, FRAME_DISPLAY_INFO (f), menu_id, true);
diff --git a/src/xterm.c b/src/xterm.c
index 80d34c114d4..de3129fd87c 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -665,6 +665,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#ifdef USE_MOTIF
#include <Xm/Xm.h>
+#include <Xm/CascadeB.h>
#endif
#ifdef USE_X_TOOLKIT
@@ -867,6 +868,10 @@ static int x_filter_event (struct x_display_info *, XEvent *);
/* Flag that indicates if a drag-and-drop operation is in progress. */
bool x_dnd_in_progress;
+/* Number that indicates the last "generation" of
+ UNSUPPORTED_DROP_EVENTs handled. */
+unsigned x_dnd_unsupported_event_level;
+
/* The frame where the drag-and-drop operation originated. */
struct frame *x_dnd_frame;
@@ -3069,6 +3074,7 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
ie.kind = UNSUPPORTED_DROP_EVENT;
ie.code = (unsigned) target_window;
+ ie.modifiers = x_dnd_unsupported_event_level;
ie.arg = list3 (assq_no_quit (QXdndSelection,
dpyinfo->terminal->Vselection_alist),
targets, arg);
@@ -5352,9 +5358,16 @@ x_set_frame_alpha (struct frame *f)
&actual, &format, &n, &left,
&data);
- if (rc == Success && actual != None && data)
+ if (rc == Success && actual != None
+ && n && format == XA_CARDINAL && data)
{
unsigned long value = *(unsigned long *) data;
+
+ /* Xlib sign-extends values greater than 0x7fffffff on 64-bit
+ machines. Get the low bits by ourself. */
+
+ value &= 0xffffffff;
+
if (value == opac)
{
x_uncatch_errors ();
@@ -5744,7 +5757,8 @@ x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
}
static void
-x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p)
+x_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
+ struct draw_fringe_bitmap_params *p)
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
Display *display = FRAME_X_DISPLAY (f);
@@ -5761,15 +5775,21 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring
mono-displays, the fill style may have been changed to
FillSolid in x_draw_glyph_string_background. */
if (face->stipple)
- XSetFillStyle (display, face->gc, FillOpaqueStippled);
- else
- XSetBackground (display, face->gc, face->background);
-
- x_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny,
- true);
+ {
+ XSetFillStyle (display, face->gc, FillOpaqueStippled);
+ x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny,
+ true);
+ XSetFillStyle (display, face->gc, FillSolid);
- if (!face->stipple)
- XSetForeground (display, face->gc, face->foreground);
+ row->stipple_p = true;
+ }
+ else
+ {
+ XSetBackground (display, face->gc, face->background);
+ x_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny,
+ true);
+ XSetForeground (display, face->gc, face->foreground);
+ }
}
#ifdef USE_CAIRO
@@ -6932,11 +6952,12 @@ x_parse_color (struct frame *f, const char *color_name,
XColor *color)
{
unsigned short r, g, b;
- Display *dpy = FRAME_X_DISPLAY (f);
- Colormap cmap = FRAME_X_COLORMAP (f);
+ Display *dpy;
+ Colormap cmap;
struct x_display_info *dpyinfo;
struct color_name_cache_entry *cache_entry;
unsigned int hash, idx;
+ int rc;
/* Don't pass #RGB strings directly to XParseColor, because that
follows the X convention of zero-extending each channel
@@ -6948,37 +6969,49 @@ x_parse_color (struct frame *f, const char *color_name,
color->red = r;
color->green = g;
color->blue = b;
+
return 1;
}
+ /* Some X servers send BadValue on empty color names. */
+ if (!strlen (color_name))
+ return 0;
+
+ cmap = FRAME_X_COLORMAP (f);
+ dpy = FRAME_X_DISPLAY (f);
dpyinfo = FRAME_DISPLAY_INFO (f);
+
hash = x_hash_string_ignore_case (color_name);
idx = hash % dpyinfo->color_names_size;
- for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names[idx];
+ for (cache_entry = dpyinfo->color_names[idx];
cache_entry; cache_entry = cache_entry->next)
{
if (!xstrcasecmp (cache_entry->name, color_name))
{
- *color = cache_entry->rgb;
- return 1;
+ if (cache_entry->valid)
+ *color = cache_entry->rgb;
+
+ return cache_entry->valid;
}
}
- /* Some X servers send BadValue on empty color names. */
- if (!strlen (color_name))
- return 0;
-
- if (XParseColor (dpy, cmap, color_name, color) == 0)
- /* No caching of negative results, currently. */
- return 0;
+ block_input ();
+ rc = XParseColor (dpy, cmap, color_name, color);
+ unblock_input ();
cache_entry = xzalloc (sizeof *cache_entry);
- cache_entry->rgb = *color;
+
+ if (rc)
+ cache_entry->rgb = *color;
+
+ cache_entry->valid = rc;
cache_entry->name = xstrdup (color_name);
- cache_entry->next = FRAME_DISPLAY_INFO (f)->color_names[idx];
- FRAME_DISPLAY_INFO (f)->color_names[idx] = cache_entry;
- return 1;
+ cache_entry->next = dpyinfo->color_names[idx];
+
+ dpyinfo->color_names[idx] = cache_entry;
+
+ return rc;
}
@@ -8038,6 +8071,9 @@ x_draw_image_glyph_string (struct glyph_string *s)
|| s->img->pixmap == 0
|| s->width != s->background_width)
{
+ if (s->stippled_p)
+ s->row->stipple_p = true;
+
#ifndef USE_CAIRO
if (s->img->mask)
{
@@ -8218,6 +8254,8 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
XSetFillStyle (display, gc, FillOpaqueStippled);
x_fill_rectangle (s->f, gc, x, y, w, h, true);
XSetFillStyle (display, gc, FillSolid);
+
+ s->row->stipple_p = true;
}
else
{
@@ -8244,8 +8282,13 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
background_width -= text_left_x - x;
x = text_left_x;
}
+
+ if (!s->row->stipple_p)
+ s->row->stipple_p = s->stippled_p;
+
if (background_width > 0)
- x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
+ x_draw_glyph_string_bg_rect (s, x, s->y,
+ background_width, s->height);
}
s->background_filled_p = true;
@@ -8694,6 +8737,14 @@ x_draw_glyph_string (struct glyph_string *s)
/* Reset clipping. */
x_reset_clip_rectangles (s->f, s->gc);
s->num_clips = 0;
+
+ /* Set the stippled flag that tells redisplay whether or not a
+ stipple was actually draw. */
+
+ if (s->first_glyph->type != STRETCH_GLYPH
+ && s->first_glyph->type != IMAGE_GLYPH
+ && !s->row->stipple_p)
+ s->row->stipple_p = s->stippled_p;
}
/* Shift display to make room for inserted glyphs. */
@@ -9438,8 +9489,24 @@ x_toggle_visible_pointer (struct frame *f, bool invisible)
if (dpyinfo->invisible_cursor == None)
dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo);
+#ifndef HAVE_XFIXES
if (dpyinfo->invisible_cursor == None)
invisible = false;
+#else
+ /* But if Xfixes is available, try using it instead. */
+ if (dpyinfo->invisible_cursor == None)
+ {
+ if (x_probe_xfixes_extension (dpyinfo))
+ {
+ dpyinfo->fixes_pointer_blanking = true;
+ xfixes_toggle_visible_pointer (f, invisible);
+
+ return;
+ }
+ else
+ invisible = false;
+ }
+#endif
if (invisible)
XDefineCursor (dpyinfo->display, FRAME_X_WINDOW (f),
@@ -9815,6 +9882,64 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
#ifndef USE_GTK
struct x_display_info *event_display;
#endif
+ union buffered_input_event *events, *event;
+ int n_events;
+ struct frame *event_frame;
+
+ /* Before starting drag-and-drop, walk through the keyboard buffer
+ to see if there are any UNSUPPORTED_DROP_EVENTs, and run them now
+ if they exist, to prevent race conditions from happening due to
+ multiple unsupported drops running at once. */
+
+ block_input ();
+ events = alloca (sizeof *events * KBD_BUFFER_SIZE);
+ n_events = 0;
+ event = kbd_fetch_ptr;
+
+ while (event != kbd_store_ptr)
+ {
+ if (event->ie.kind == UNSUPPORTED_DROP_EVENT
+ && event->ie.modifiers < x_dnd_unsupported_event_level)
+ events[n_events++] = *event;
+
+ event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
+ ? kbd_buffer : event + 1);
+ }
+
+ x_dnd_unsupported_event_level += 1;
+ unblock_input ();
+
+ for (i = 0; i < n_events; ++i)
+ {
+ maybe_quit ();
+
+ event = &events[i];
+ event_frame = XFRAME (event->ie.frame_or_window);
+
+ if (!FRAME_LIVE_P (event_frame))
+ continue;
+
+ if (!NILP (Vx_dnd_unsupported_drop_function))
+ {
+ if (!NILP (call7 (Vx_dnd_unsupported_drop_function,
+ XCAR (XCDR (event->ie.arg)), event->ie.x,
+ event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
+ make_uint (event->ie.code),
+ event->ie.frame_or_window,
+ make_int (event->ie.timestamp))))
+ continue;
+ }
+
+ x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (event_frame),
+ event->ie.frame_or_window,
+ XCAR (event->ie.arg),
+ XCAR (XCDR (event->ie.arg)),
+ (Window) event->ie.code,
+ XFIXNUM (event->ie.x),
+ XFIXNUM (event->ie.y),
+ event->ie.timestamp);
+ break;
+ }
if (!FRAME_VISIBLE_P (f))
{
@@ -10035,116 +10160,133 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
unblock_input ();
pending_signals = signals_were_pending;
- if (x_dnd_movement_frame)
- {
- XSETFRAME (frame_object, x_dnd_movement_frame);
- XSETINT (x, x_dnd_movement_x);
- XSETINT (y, x_dnd_movement_y);
- x_dnd_movement_frame = NULL;
-
- if (!NILP (Vx_dnd_movement_function)
- && !FRAME_TOOLTIP_P (XFRAME (frame_object))
- && x_dnd_movement_x >= 0
- && x_dnd_movement_y >= 0
- && x_dnd_frame
- && (XFRAME (frame_object) != x_dnd_frame
- || x_dnd_allow_current_frame))
- {
- x_dnd_old_window_attrs = root_window_attrs;
- x_dnd_unwind_flag = true;
-
- ref = SPECPDL_INDEX ();
- record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
- call2 (Vx_dnd_movement_function, frame_object,
- Fposn_at_x_y (x, y, frame_object, Qnil));
- x_dnd_unwind_flag = false;
- unbind_to (ref, Qnil);
- }
- }
-
- if (hold_quit.kind != NO_EVENT)
+ /* Ignore mouse movement from displays that aren't the DND
+ display. */
+#ifndef USE_GTK
+ if (event_display == FRAME_DISPLAY_INFO (f))
{
- if (hold_quit.kind == SELECTION_REQUEST_EVENT)
+#endif
+ if (x_dnd_movement_frame)
{
- x_dnd_old_window_attrs = root_window_attrs;
- x_dnd_unwind_flag = true;
-
- ref = SPECPDL_INDEX ();
- record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
- x_handle_selection_event ((struct selection_input_event *) &hold_quit);
- x_dnd_unwind_flag = false;
- unbind_to (ref, Qnil);
- continue;
+ XSETFRAME (frame_object, x_dnd_movement_frame);
+ XSETINT (x, x_dnd_movement_x);
+ XSETINT (y, x_dnd_movement_y);
+ x_dnd_movement_frame = NULL;
+
+ if (!NILP (Vx_dnd_movement_function)
+ && !FRAME_TOOLTIP_P (XFRAME (frame_object))
+ && x_dnd_movement_x >= 0
+ && x_dnd_movement_y >= 0
+ && x_dnd_frame
+ && (XFRAME (frame_object) != x_dnd_frame
+ || x_dnd_allow_current_frame))
+ {
+ x_dnd_old_window_attrs = root_window_attrs;
+ x_dnd_unwind_flag = true;
+
+ ref = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+ call2 (Vx_dnd_movement_function, frame_object,
+ Fposn_at_x_y (x, y, frame_object, Qnil));
+ x_dnd_unwind_flag = false;
+ unbind_to (ref, Qnil);
+ }
}
- if (x_dnd_in_progress)
+ if (hold_quit.kind != NO_EVENT)
{
- if (x_dnd_last_seen_window != None
- && x_dnd_last_protocol_version != -1)
- x_dnd_send_leave (f, x_dnd_last_seen_window);
- else if (x_dnd_last_seen_window != None
- && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
- && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
- && x_dnd_motif_setup_p)
+ if (hold_quit.kind == SELECTION_REQUEST_EVENT)
{
- dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
- XM_DRAG_REASON_DROP_START);
- dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
- dmsg.timestamp = hold_quit.timestamp;
- dmsg.side_effects
- = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
- x_dnd_wanted_action),
- XM_DROP_SITE_VALID,
- xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
- x_dnd_wanted_action),
- XM_DROP_ACTION_DROP_CANCEL);
- dmsg.x = 0;
- dmsg.y = 0;
- dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
- dmsg.source_window = FRAME_X_WINDOW (f);
-
- x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
- x_dnd_last_seen_window,
- hold_quit.timestamp);
- xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
- x_dnd_last_seen_window, &dmsg);
+ x_dnd_old_window_attrs = root_window_attrs;
+ x_dnd_unwind_flag = true;
+
+ ref = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+ x_handle_selection_event ((struct selection_input_event *) &hold_quit);
+ x_dnd_unwind_flag = false;
+ unbind_to (ref, Qnil);
+ continue;
}
- x_dnd_end_window = x_dnd_last_seen_window;
- x_dnd_last_seen_window = None;
- x_dnd_last_seen_toplevel = None;
- x_dnd_in_progress = false;
- x_dnd_frame = NULL;
- }
+ if (x_dnd_in_progress)
+ {
+ if (x_dnd_last_seen_window != None
+ && x_dnd_last_protocol_version != -1)
+ x_dnd_send_leave (f, x_dnd_last_seen_window);
+ else if (x_dnd_last_seen_window != None
+ && !XM_DRAG_STYLE_IS_DROP_ONLY (x_dnd_last_motif_style)
+ && x_dnd_last_motif_style != XM_DRAG_STYLE_NONE
+ && x_dnd_motif_setup_p)
+ {
+ dmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR,
+ XM_DRAG_REASON_DROP_START);
+ dmsg.byte_order = XM_BYTE_ORDER_CUR_FIRST;
+ dmsg.timestamp = hold_quit.timestamp;
+ dmsg.side_effects
+ = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ x_dnd_wanted_action),
+ XM_DROP_SITE_VALID,
+ xm_side_effect_from_action (FRAME_DISPLAY_INFO (f),
+ x_dnd_wanted_action),
+ XM_DROP_ACTION_DROP_CANCEL);
+ dmsg.x = 0;
+ dmsg.y = 0;
+ dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+ dmsg.source_window = FRAME_X_WINDOW (f);
+
+ x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
+ x_dnd_last_seen_window,
+ hold_quit.timestamp);
+ xm_send_drop_message (FRAME_DISPLAY_INFO (f), FRAME_X_WINDOW (f),
+ x_dnd_last_seen_window, &dmsg);
+ }
- x_set_dnd_targets (NULL, 0);
- x_dnd_waiting_for_finish = false;
+ x_dnd_end_window = x_dnd_last_seen_window;
+ x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
+ x_dnd_in_progress = false;
+ x_dnd_frame = NULL;
+ }
- if (x_dnd_use_toplevels)
- x_dnd_free_toplevels ();
+ x_set_dnd_targets (NULL, 0);
+ x_dnd_waiting_for_finish = false;
- x_dnd_return_frame_object = NULL;
- x_dnd_movement_frame = NULL;
+ if (x_dnd_use_toplevels)
+ x_dnd_free_toplevels ();
- FRAME_DISPLAY_INFO (f)->grabbed = 0;
+ x_dnd_return_frame_object = NULL;
+ x_dnd_movement_frame = NULL;
+
+ FRAME_DISPLAY_INFO (f)->grabbed = 0;
#ifdef USE_GTK
- current_hold_quit = NULL;
+ current_hold_quit = NULL;
#endif
- /* Restore the old event mask. */
- XSelectInput (FRAME_X_DISPLAY (f),
- FRAME_DISPLAY_INFO (f)->root_window,
- root_window_attrs.your_event_mask);
+ /* Restore the old event mask. */
+ XSelectInput (FRAME_X_DISPLAY (f),
+ FRAME_DISPLAY_INFO (f)->root_window,
+ root_window_attrs.your_event_mask);
#ifdef HAVE_XKB
- if (FRAME_DISPLAY_INFO (f)->supports_xkb)
- XkbSelectEvents (FRAME_X_DISPLAY (f), XkbUseCoreKbd,
- XkbStateNotifyMask, 0);
+ if (FRAME_DISPLAY_INFO (f)->supports_xkb)
+ XkbSelectEvents (FRAME_X_DISPLAY (f), XkbUseCoreKbd,
+ XkbStateNotifyMask, 0);
#endif
- /* Delete the Motif drag initiator info if it was set up. */
- if (x_dnd_motif_setup_p)
- XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
- quit ();
+ /* Delete the Motif drag initiator info if it was set up. */
+ if (x_dnd_motif_setup_p)
+ XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+ quit ();
+ }
+#ifndef USE_GTK
+ }
+ else
+ {
+ if (x_dnd_movement_frame)
+ x_dnd_movement_frame = NULL;
+
+ if (hold_quit.kind != NO_EVENT)
+ EVENT_INIT (hold_quit);
}
+#endif
}
x_set_dnd_targets (NULL, 0);
@@ -10316,12 +10458,21 @@ x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
}
-#if !defined USE_X_TOOLKIT && !defined USE_GTK
+#if (defined USE_LUCID && defined HAVE_XINPUT2) \
+ || (!defined USE_X_TOOLKIT && !defined USE_GTK)
/* Handle an event saying the mouse has moved out of an Emacs frame. */
void
x_mouse_leave (struct x_display_info *dpyinfo)
{
+ Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
+
+ if (hlinfo->mouse_face_mouse_frame)
+ {
+ clear_mouse_face (hlinfo);
+ hlinfo->mouse_face_mouse_frame = NULL;
+ }
+
x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
}
#endif
@@ -13912,6 +14063,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -13951,6 +14103,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -13976,7 +14129,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
- else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -14007,7 +14161,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp)
0
#endif
);
- else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -14598,7 +14753,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
unsigned long nitems, bytesafter;
unsigned char *data = NULL;
-
if (event->xproperty.state == PropertyDelete)
{
if (!last)
@@ -14687,6 +14841,44 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
}
+ if (f && FRAME_X_OUTPUT (f)->alpha_identical_p
+ && (event->xproperty.atom
+ == dpyinfo->Xatom_net_wm_window_opacity))
+ {
+ int rc, actual_format;
+ Atom actual;
+ unsigned char *tmp_data;
+ unsigned long n, left, opacity;
+
+ tmp_data = NULL;
+
+ if (event->xproperty.state == PropertyDelete)
+ {
+ f->alpha[0] = 1.0;
+ f->alpha[1] = 1.0;
+ }
+ else
+ {
+ rc = XGetWindowProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
+ dpyinfo->Xatom_net_wm_window_opacity,
+ 0, 1, False, XA_CARDINAL, &actual,
+ &actual_format, &n, &left, &tmp_data);
+
+ if (rc == Success && actual_format == 32
+ && actual == XA_CARDINAL && n)
+ {
+ opacity = *(unsigned long *) tmp_data & OPAQUE;
+ f->alpha[0] = (double) opacity / (double) OPAQUE;
+ f->alpha[1] = (double) opacity / (double) OPAQUE;
+
+ store_frame_param (f, Qalpha, make_float (f->alpha[0]));
+ }
+ }
+
+ if (tmp_data)
+ XFree (tmp_data);
+ }
+
if (event->xproperty.window == dpyinfo->root_window
&& (event->xproperty.atom == dpyinfo->Xatom_net_client_list_stacking
|| event->xproperty.atom == dpyinfo->Xatom_net_current_desktop)
@@ -14985,7 +15177,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
popup_activated_flag = 1;
#endif
- if (x_dnd_in_progress)
+ if (x_dnd_in_progress
+ && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
x_dnd_update_state (dpyinfo, dpyinfo->last_user_time);
if (x_dnd_in_progress && x_dnd_use_toplevels
@@ -15733,6 +15926,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -15772,6 +15966,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -15818,7 +16013,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
- else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -15845,7 +16041,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_selection_timestamp,
x_dnd_wanted_action, 0,
event->xmotion.state);
- else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -16250,7 +16447,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
- if (x_dnd_in_progress)
+ if (x_dnd_in_progress
+ && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
x_dnd_update_state (dpyinfo, dpyinfo->last_user_time);
goto OTHER;
@@ -16607,14 +16805,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
&& event->xbutton.same_screen)
{
#ifdef USE_MOTIF
- unsigned char column_type;
Widget widget;
widget = XtWindowToWidget (dpyinfo->display,
event->xbutton.window);
- XtVaGetValues (widget, XmNrowColumnType, &column_type, NULL);
- if (column_type != XmMENU_BAR)
+ if (widget && XmIsCascadeButton (widget)
+ && XtIsSensitive (widget))
{
#endif
if (!f->output_data.x->saved_menu_event)
@@ -16634,7 +16831,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
break;
case CirculateNotify:
- if (x_dnd_in_progress)
+ if (x_dnd_in_progress
+ && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
x_dnd_update_state (dpyinfo, dpyinfo->last_user_time);
goto OTHER;
@@ -16765,7 +16963,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
ev.window = enter->event;
ev.time = enter->time;
- x_display_set_last_user_time (dpyinfo, xi_event->time);
+ x_display_set_last_user_time (dpyinfo, enter->time);
#ifdef USE_MOTIF
use_copy = true;
@@ -16867,7 +17065,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#ifdef USE_X_TOOLKIT
if (popup_activated ()
- && leave->mode == XINotifyPassiveUngrab)
+ && (leave->mode == XINotifyPassiveUngrab
+ || leave->mode == XINotifyUngrab))
any = x_any_window_to_frame (dpyinfo, leave->event);
#endif
@@ -16912,7 +17111,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
leave->deviceid, false);
#endif
- x_display_set_last_user_time (dpyinfo, xi_event->time);
+ x_display_set_last_user_time (dpyinfo, leave->time);
#ifdef HAVE_XWIDGETS
{
@@ -17310,6 +17509,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -17349,6 +17549,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window);
else if (x_dnd_last_seen_window != None
&& XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
{
if (!x_dnd_motif_setup_p)
@@ -17397,7 +17598,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (target != None && x_dnd_last_protocol_version != -1)
x_dnd_send_enter (x_dnd_frame, target,
x_dnd_last_protocol_version);
- else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style))
+ else if (target != None && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style)
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -17437,7 +17639,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_dnd_wanted_action, 0,
dnd_state);
}
- else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None)
+ else if (XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) && target != None
+ && !x_dnd_disable_motif_drag)
{
if (!x_dnd_motif_setup_p)
xm_setup_drag_info (dpyinfo, x_dnd_frame);
@@ -17529,7 +17732,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
{
#ifndef USE_TOOLKIT_SCROLL_BARS
struct scroll_bar *bar
- = x_window_to_scroll_bar (xi_event->display, xev->event, 2);
+ = x_window_to_scroll_bar (dpyinfo->display, xev->event, 2);
if (bar)
x_scroll_bar_note_movement (bar, &ev);
@@ -19106,7 +19309,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
device = xi_device_from_id (dpyinfo, pev->deviceid);
source = xi_device_from_id (dpyinfo, pev->sourceid);
- x_display_set_last_user_time (dpyinfo, xi_event->time);
+ x_display_set_last_user_time (dpyinfo, pev->time);
if (!device)
goto XI_OTHER;
@@ -24762,6 +24965,13 @@ during a drag-and-drop session, to work around broken implementations
of Motif. */);
x_dnd_fix_motif_leave = true;
+ DEFVAR_BOOL ("x-dnd-disable-motif-drag", x_dnd_disable_motif_drag,
+ doc: /* Disable the Motif drag protocol during DND.
+This reduces network usage, but also means you can no longer scroll
+around inside the Motif window underneath the cursor during
+drag-and-drop. */);
+ x_dnd_disable_motif_drag = false;
+
DEFVAR_LISP ("x-dnd-movement-function", Vx_dnd_movement_function,
doc: /* Function called upon mouse movement on a frame during drag-and-drop.
It should either be nil, or accept two arguments FRAME and POSITION,
@@ -24771,16 +24981,16 @@ mouse position list. */);
DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function,
doc: /* Function called when trying to drop on an unsupported window.
-This function is called whenever the user tries to drop
-something on a window that does not support either the XDND or
-Motif protocols for drag-and-drop. It should return a non-nil
-value if the drop was handled by the function, and nil if it was
-not. It should accept several arguments TARGETS, X, Y, ACTION,
-WINDOW-ID and FRAME, where TARGETS is the list of targets that
-was passed to `x-begin-drag', WINDOW-ID is the numeric XID of
-the window that is being dropped on, X and Y are the root
-window-relative coordinates where the drop happened, ACTION
-is the action that was passed to `x-begin-drag', and FRAME is
-the frame which initiated the drag-and-drop operation. */);
+This function is called whenever the user tries to drop something on a
+window that does not support either the XDND or Motif protocols for
+drag-and-drop. It should return a non-nil value if the drop was
+handled by the function, and nil if it was not. It should accept
+several arguments TARGETS, X, Y, ACTION, WINDOW-ID, FRAME and TIME,
+where TARGETS is the list of targets that was passed to
+`x-begin-drag', WINDOW-ID is the numeric XID of the window that is
+being dropped on, X and Y are the root window-relative coordinates
+where the drop happened, ACTION is the action that was passed to
+`x-begin-drag', FRAME is the frame which initiated the drag-and-drop
+operation, and TIME is the X server time when the drop happened. */);
Vx_dnd_unsupported_drop_function = Qnil;
}
diff --git a/src/xterm.h b/src/xterm.h
index 74e6d1a96cb..98c4c5f01c6 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -196,8 +196,15 @@ extern cairo_pattern_t *x_bitmap_stipple (struct frame *, Pixmap);
struct color_name_cache_entry
{
struct color_name_cache_entry *next;
+
+ /* The color values of the cached color entry. */
XColor rgb;
+
+ /* The name of the cached color. */
char *name;
+
+ /* Whether or not RGB is valid (i.e. the color actually exists). */
+ bool_bf valid : 1;
};
#ifdef HAVE_XINPUT2
@@ -925,6 +932,10 @@ struct x_output
false, tell Xt not to wait. */
bool_bf wait_for_wm : 1;
+ /* True if this frame's alpha value is the same for both the active
+ and inactive states. */
+ bool_bf alpha_identical_p : 1;
+
#ifdef HAVE_X_I18N
/* Input context (currently, this means Compose key handler setup). */
XIC xic;
@@ -1386,7 +1397,8 @@ extern bool x_alloc_lighter_color_for_widget (Widget, Display *, Colormap,
extern bool x_alloc_nearest_color (struct frame *, Colormap, XColor *);
extern void x_query_colors (struct frame *f, XColor *, int);
extern void x_clear_area (struct frame *f, int, int, int, int);
-#if !defined USE_X_TOOLKIT && !defined USE_GTK
+#if (defined USE_LUCID && defined HAVE_XINPUT2) \
+ || (!defined USE_X_TOOLKIT && !defined USE_GTK)
extern void x_mouse_leave (struct x_display_info *);
#endif
@@ -1578,6 +1590,7 @@ extern struct input_event xg_pending_quit_event;
extern bool x_dnd_in_progress;
extern struct frame *x_dnd_frame;
+extern unsigned x_dnd_unsupported_event_level;
#ifdef HAVE_XINPUT2
extern struct xi_device_t *xi_device_from_id (struct x_display_info *, int);
diff --git a/test/lisp/emacs-lisp/easy-mmode-tests.el b/test/lisp/emacs-lisp/easy-mmode-tests.el
index 0a3bbb189ba..f6d07196727 100644
--- a/test/lisp/emacs-lisp/easy-mmode-tests.el
+++ b/test/lisp/emacs-lisp/easy-mmode-tests.el
@@ -60,6 +60,4 @@
(easy-mmode-test-mode 'toggle)
(should (eq easy-mmode-test-mode t))))
-(provide 'easy-mmode-tests)
-
;;; easy-mmode-tests.el ends here
diff --git a/test/lisp/help-mode-tests.el b/test/lisp/help-mode-tests.el
index c0c1cf8b530..b5bdf6b8d49 100644
--- a/test/lisp/help-mode-tests.el
+++ b/test/lisp/help-mode-tests.el
@@ -81,7 +81,7 @@ Lisp concepts such as car, cdr, cons cell and list.")
(insert (format fmt fn))
(goto-char (point-min))
(re-search-forward help-xref-symbol-regexp)
- (help-xref-button 8 'help-function)
+ (help-xref-button 9 'help-function)
(should-not (button-at (1- beg)))
(should-not (button-at (+ beg (length (symbol-name fn)))))
(should (eq (button-type (button-at beg)) 'help-function))))))
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 2d2bef732e0..643e19c1d2d 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -65,9 +65,6 @@
(declare-function tramp-method-out-of-band-p "tramp-sh")
(declare-function tramp-smb-get-localname "tramp-smb")
(defvar ange-ftp-make-backup-files)
-(defvar auto-save-file-name-transforms)
-(defvar lock-file-name-transforms)
-(defvar remote-file-name-inhibit-locks)
(defvar tramp-connection-properties)
(defvar tramp-copy-size-limit)
(defvar tramp-display-escape-sequence-regexp)
@@ -77,12 +74,59 @@
(defvar tramp-remote-path)
(defvar tramp-remote-process-environment)
+;; Needed for Emacs 26.
+(declare-function with-connection-local-variables "files-x")
;; Needed for Emacs 27.
+(defvar lock-file-name-transforms)
(defvar process-file-return-signal-string)
+(defvar remote-file-name-inhibit-locks)
(defvar shell-command-dont-erase-buffer)
;; Needed for Emacs 28.
(defvar dired-copy-dereference)
+;; `ert-resource-file' was introduced in Emacs 28.1.
+(unless (macrop 'ert-resource-file)
+ (eval-and-compile
+ (defvar ert-resource-directory-format "%s-resources/"
+ "Format for `ert-resource-directory'.")
+ (defvar ert-resource-directory-trim-left-regexp ""
+ "Regexp for `string-trim' (left) used by `ert-resource-directory'.")
+ (defvar ert-resource-directory-trim-right-regexp "\\(-tests?\\)?\\.el"
+ "Regexp for `string-trim' (right) used by `ert-resource-directory'.")
+
+ (defmacro ert-resource-directory ()
+ "Return absolute file name of the resource directory for this file.
+
+The path to the resource directory is the \"resources\" directory
+in the same directory as the test file.
+
+If that directory doesn't exist, use the directory named like the
+test file but formatted by `ert-resource-directory-format' and trimmed
+using `string-trim' with arguments
+`ert-resource-directory-trim-left-regexp' and
+`ert-resource-directory-trim-right-regexp'. The default values mean
+that if called from a test file named \"foo-tests.el\", return
+the absolute file name for \"foo-resources\"."
+ `(let* ((testfile ,(or (bound-and-true-p byte-compile-current-file)
+ (and load-in-progress load-file-name)
+ buffer-file-name))
+ (default-directory (file-name-directory testfile)))
+ (file-truename
+ (if (file-accessible-directory-p "resources/")
+ (expand-file-name "resources/")
+ (expand-file-name
+ (format
+ ert-resource-directory-format
+ (string-trim testfile
+ ert-resource-directory-trim-left-regexp
+ ert-resource-directory-trim-right-regexp)))))))
+
+ (defmacro ert-resource-file (file)
+ "Return file name of resource file named FILE.
+A resource file is in the resource directory as per
+`ert-resource-directory'."
+ `(expand-file-name ,file (ert-resource-directory)))))
+
;; Beautify batch mode.
(when noninteractive
;; Suppress nasty messages.
@@ -2505,7 +2549,9 @@ This checks also `file-name-as-directory', `file-name-directory',
(setq-local file-precious-flag t)
(setq-local backup-inhibited t)
(insert "bar")
+ (should (buffer-modified-p))
(should (null (save-buffer)))
+ (should (not (buffer-modified-p)))
(should-not (cl-member tmp-name written-files :test #'string=)))
;; Cleanup.
@@ -2518,6 +2564,8 @@ This checks also `file-name-as-directory', `file-name-directory',
(skip-unless (tramp--test-enabled))
(skip-unless (not (tramp--test-ange-ftp-p)))
(skip-unless (executable-find "gzip"))
+ ;; The function was introduced in Emacs 28.1.
+ (skip-unless (boundp 'tar-goto-file))
(let* ((default-directory tramp-test-temporary-file-directory)
(archive (ert-resource-file "foo.tar.gz"))
@@ -2531,20 +2579,26 @@ This checks also `file-name-as-directory', `file-name-directory',
(copy-file archive tmp-file 'ok)
;; Read archive. Check contents of foo.txt, and modify it. Save.
(with-current-buffer (setq buffer1 (find-file-noselect tmp-file))
- (should (tar-goto-file "foo.txt"))
+ ;; The function was introduced in Emacs 28.1.
+ (with-no-warnings (should (tar-goto-file "foo.txt")))
(save-current-buffer
(setq buffer2 (tar-extract))
(should (string-equal (buffer-string) "foo\n"))
(goto-char (point-max))
(insert "bar")
- (should (null (save-buffer))))
- (should (null (save-buffer))))
+ (should (buffer-modified-p))
+ (should (null (save-buffer)))
+ (should-not (buffer-modified-p)))
+ (should (buffer-modified-p))
+ (should (null (save-buffer)))
+ (should-not (buffer-modified-p)))
(kill-buffer buffer1)
(kill-buffer buffer2)
;; Read archive. Check contents of modified foo.txt.
(with-current-buffer (setq buffer1 (find-file-noselect tmp-file))
- (should (tar-goto-file "foo.txt"))
+ ;; The function was introduced in Emacs 28.1.
+ (with-no-warnings (should (tar-goto-file "foo.txt")))
(save-current-buffer
(setq buffer2 (tar-extract))
(should (string-equal (buffer-string) "foo\nbar\n")))))
@@ -5032,6 +5086,8 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
(skip-unless (not (tramp--test-crypt-p)))
+ ;; Since Emacs 27.1.
+ (skip-unless (macrop 'with-connection-local-variables))
;; We must use `file-truename' for the temporary directory, in
;; order to establish the connection prior running an asynchronous
@@ -5072,6 +5128,8 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
(skip-unless (not (tramp--test-crypt-p)))
+ ;; Since Emacs 27.1.
+ (skip-unless (macrop 'with-connection-local-variables))
;; Since Emacs 29.1.
(skip-unless (boundp 'signal-process-functions))
@@ -5117,10 +5175,12 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
(should (equal (process-get proc 'remote-command)
(with-connection-local-variables
`(,shell-file-name ,shell-command-switch ,command))))
- (should
- (zerop
- (signal-process
- (process-get proc 'remote-pid) sigcode default-directory)))
+ ;; `signal-process' has argument REMOTE since Emacs 29.
+ (with-no-warnings
+ (should
+ (zerop
+ (signal-process
+ (process-get proc 'remote-pid) sigcode default-directory))))
;; Let the process accept the signal.
(with-timeout (10 (tramp--test-timeout-handler))
(while (accept-process-output proc 0 nil t)))
@@ -5181,9 +5241,11 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
INPUT, if non-nil, is a string sent to the process."
(let ((proc (async-shell-command command output-buffer error-buffer))
(delete-exited-processes t))
- (should (equal (process-get proc 'remote-command)
- (with-connection-local-variables
- `(,shell-file-name ,shell-command-switch ,command))))
+ ;; Since Emacs 27.1.
+ (when (macrop 'with-connection-local-variables)
+ (should (equal (process-get proc 'remote-command)
+ (with-connection-local-variables
+ `(,shell-file-name ,shell-command-switch ,command)))))
(cl-letf (((symbol-function #'shell-command-sentinel) #'ignore))
(when (stringp input)
(process-send-string proc input))
@@ -5567,7 +5629,7 @@ Use direct async.")
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
;; Since Emacs 27.1.
- (skip-unless (fboundp 'with-connection-local-variables))
+ (skip-unless (macrop 'with-connection-local-variables))
(let* ((default-directory tramp-test-temporary-file-directory)
(tmp-name1 (tramp--test-make-temp-name))
@@ -5583,6 +5645,8 @@ Use direct async.")
(should (file-directory-p tmp-name1))
;; `local-variable' is buffer-local due to explicit setting.
+ ;; We need `with-no-warnings', because `defvar-local' is not
+ ;; called at toplevel.
(with-no-warnings
(defvar-local local-variable 'buffer))
(with-temp-buffer
@@ -6163,7 +6227,9 @@ Use direct async.")
(with-temp-buffer
(set-visited-file-name tmp-name1)
(insert "foo")
- (save-buffer))
+ (should (buffer-modified-p))
+ (save-buffer)
+ (should-not (buffer-modified-p)))
(should-not (with-no-warnings (file-locked-p tmp-name1)))
(with-no-warnings (lock-file tmp-name1))
(should (eq (with-no-warnings (file-locked-p tmp-name1)) t))
@@ -6285,7 +6351,9 @@ Use direct async.")
;; buffer results in a prompt.
(cl-letf (((symbol-function 'yes-or-no-p)
(lambda (_) (ert-fail "Test failed unexpectedly"))))
- (save-buffer))
+ (should (buffer-modified-p))
+ (save-buffer)
+ (should-not (buffer-modified-p)))
(should-not (file-locked-p tmp-name))
;; For local files, just changing the file
@@ -6317,7 +6385,9 @@ Use direct async.")
(cl-letf (((symbol-function 'yes-or-no-p) #'tramp--test-always)
((symbol-function 'read-char-choice)
(lambda (&rest _) ?y)))
- (save-buffer))
+ (should (buffer-modified-p))
+ (save-buffer)
+ (should-not (buffer-modified-p)))
(should-not (file-locked-p tmp-name))))
;; Cleanup.
diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el
index 3725f180f3a..89803e5ce2e 100644
--- a/test/lisp/subr-tests.el
+++ b/test/lisp/subr-tests.el
@@ -1058,5 +1058,21 @@ final or penultimate step during initialization."))
(should (equal (kbd "C-x ( C-d C-x )") ""))
(should (equal (kbd "C-x ( C-x )") "")))
+(defvar subr-test--global)
+(ert-deftest test-local-set-state ()
+ (setq subr-test--global 1)
+ (with-temp-buffer
+ (setq-local subr-test--local 2)
+ (let ((state (buffer-local-set-state subr-test--global 10
+ subr-test--local 20
+ subr-test--unexist 30)))
+ (should (= subr-test--global 10))
+ (should (= subr-test--local 20))
+ (should (= subr-test--unexist 30))
+ (buffer-local-restore-state state)
+ (should (= subr-test--global 1))
+ (should (= subr-test--local 2))
+ (should-not (boundp 'subr-test--unexist)))))
+
(provide 'subr-tests)
;;; subr-tests.el ends here
diff --git a/test/src/buffer-tests.el b/test/src/buffer-tests.el
index c1e5d0ebed3..10dac68f9fe 100644
--- a/test/src/buffer-tests.el
+++ b/test/src/buffer-tests.el
@@ -1482,4 +1482,39 @@ with parameters from the *Messages* buffer modification."
(when auto-save
(ignore-errors (delete-file auto-save))))))))
+(ert-deftest test-buffer-modifications ()
+ (ert-with-temp-file file
+ (with-current-buffer (find-file file)
+ (auto-save-mode 1)
+ (should-not (buffer-modified-p))
+ (insert "foo")
+ (should (buffer-modified-p))
+ (should-not (eq (buffer-modified-p) 'autosaved))
+ (do-auto-save nil t)
+ (should (eq (buffer-modified-p) 'autosaved))
+ (with-silent-modifications
+ (put-text-property 1 3 'face 'bold))
+ (should (eq (buffer-modified-p) 'autosaved))
+ (save-buffer)
+ (should-not (buffer-modified-p))
+ (with-silent-modifications
+ (put-text-property 1 3 'face 'italic))
+ (should-not (buffer-modified-p)))))
+
+(ert-deftest test-restore-buffer-modified-p ()
+ (ert-with-temp-file file
+ (with-current-buffer (find-file file)
+ (auto-save-mode 1)
+ (should-not (buffer-modified-p))
+ (insert "foo")
+ (should (buffer-modified-p))
+ (restore-buffer-modified-p nil)
+ (should-not (buffer-modified-p))
+ (insert "bar")
+ (do-auto-save nil t)
+ (should (eq (buffer-modified-p) 'autosaved))
+ (insert "zot")
+ (restore-buffer-modified-p 'autosaved)
+ (should (eq (buffer-modified-p) 'autosaved)))))
+
;;; buffer-tests.el ends here
diff --git a/test/src/image-tests.el b/test/src/image-tests.el
index 3885981e0b2..f710aadea74 100644
--- a/test/src/image-tests.el
+++ b/test/src/image-tests.el
@@ -53,6 +53,8 @@
;;;; image-test-size
+(declare-function image-size "image.c" (spec &optional pixels frame))
+
(ert-deftest image-tests-image-size/gif ()
(image-skip-unless 'gif)
(pcase (image-size (create-image (cdr (assq 'gif image-tests--images))))
@@ -126,6 +128,8 @@
;;;; image-mask-p
+(declare-function image-mask-p "image.c" (spec &optional frame))
+
(ert-deftest image-tests-image-mask-p/gif ()
(image-skip-unless 'gif)
(should-not (image-mask-p (create-image
@@ -176,6 +180,8 @@
;;;; image-metadata
+(declare-function image-metadata "image.c" (spec &optional frame))
+
;; TODO: These tests could be expanded with files that actually
;; contain metadata.
@@ -238,6 +244,7 @@
(ert-deftest image-tests-init-image-library ()
(skip-unless (fboundp 'init-image-library))
+ (declare-function init-image-library "image.c" (type))
(should (init-image-library 'pbm)) ; built-in
(should-not (init-image-library 'invalid-image-type)))