diff options
author | Sean Whitton <spwhitton@spwhitton.name> | 2022-05-09 18:51:10 -0700 |
---|---|---|
committer | Sean Whitton <spwhitton@spwhitton.name> | 2022-05-09 18:51:10 -0700 |
commit | a50ea74ec1518a9a506454e015641bf9c94ee3e4 (patch) | |
tree | 71c0fa21a7d249cd4d6865000058935c2f1d80e3 | |
parent | 9a23632f13fd116750f290e07f633cbdf8f2a78c (diff) | |
parent | 054062060e9f57fd037578378c23ad9ec294edac (diff) | |
download | emacs-a50ea74ec1518a9a506454e015641bf9c94ee3e4.tar.gz |
Merge remote-tracking branch 'origin/master' into athena/unstable
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 @@ -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))) |