Steps to take before starting on the first pretest in any release sequence:
-0. The release branch (e.g. emacs-24) should already have been made
+0. The release branch (e.g. emacs-25) should already have been made
and you should use it for all that follows. Diffs from this
branch should be going to the emacs-diffs mailing list.
1. git pull # fetch from the repository
git status # check for locally modified files
+ Ensure that you have a clean, unmodified state.
+ If you switched in-place from another branch to the release branch,
+ there could be inappropriate generated ignored files left over.
+ You might want to use "git status --ignored" to check for such files,
+ or some form of "git clean -x". It's probably simpler and safer to
+ make a new working directory exclusively for the release branch.
+
2. Regenerate the etc/AUTHORS file:
M-: (require 'authors) RET
M-x authors RET
@contents
-@node Top
+@node Top, Overview, (dir), (dir)
@top EasyPG Assistant user's manual
EasyPG Assistant is an Emacs user interface to GNU Privacy Guard
* Quick start::
* Commands::
* Caching Passphrases::
+* GnuPG version compatibility::
* Bug Reports::
* GNU Free Documentation License:: The license for this documentation.
* Key Index::
* Variable Index::
@end menu
-@node Overview
+@node Overview, Quick start, Top, Top
@chapter Overview
EasyPG Assistant provides the following features.
@item Automatic encryption/decryption of *.gpg files.
@end itemize
-@node Quick start
+@node Quick start, Commands, Overview, Top
@chapter Quick start
EasyPG Assistant commands are prefixed by @samp{epa-}. For example,
integrated into other Emacs functionalities. For example, automatic
encryption/decryption of @file{*.gpg} files.
-@node Commands
+@node Commands, GnuPG version compatibility, Quick start, Top
@chapter Commands
This chapter introduces various commands for typical use cases.
* Encrypting/decrypting gpg files::
@end menu
-@node Key management
+@node Key management, Cryptographic operations on regions, Commands, Commands
@section Key management
Probably the first step of using EasyPG Assistant is to browse your
keyring. @kbd{M-x epa-list-keys} is corresponding to @samp{gpg
also delete the secret keys.
@end deffn
-@node Cryptographic operations on regions
+@node Cryptographic operations on regions, Cryptographic operations on files, Key management, Commands
@section Cryptographic operations on regions
@deffn Command epa-decrypt-region start end
you answered yes, it will let you select the signing keys.
@end deffn
-@node Cryptographic operations on files
+@node Cryptographic operations on files, Dired integration, Cryptographic operations on regions, Commands
@section Cryptographic operations on files
@deffn Command epa-decrypt-file file &optional output
Encrypt @var{file}. It will let you select recipients.
@end deffn
-@node Dired integration
+@node Dired integration, Mail-mode integration, Cryptographic operations on files, Commands
@section Dired integration
EasyPG Assistant extends Dired Mode for GNU Emacs to allow users to
@end table
-@node Mail-mode integration
+@node Mail-mode integration, Encrypting/decrypting gpg files, Dired integration, Commands
@section Mail-mode integration
EasyPG Assistant provides a minor mode @code{epa-mail-mode} to help
@end table
-@node Encrypting/decrypting gpg files
+@node Encrypting/decrypting gpg files, , Mail-mode integration, Commands
@section Encrypting/decrypting gpg files
By default, every file whose name ends with @file{.gpg} will be
treated as encrypted. That is, when you open such a file, the
The default value is @code{t}.
@end defvar
-@node Caching Passphrases
+@node GnuPG version compatibility, Caching Passphrases, Commands, Top
+@chapter GnuPG version compatibility
+
+As of February 2016, there are three active branches of GnuPG: 2.1,
+2.0, and 1.4. All those branches should work flawlessly with Emacs
+with basic use-cases. They have, however, some incompatible
+characteristics, which might be visible when used from Emacs.
+
+@itemize
+@item
+The key store format used by GnuPG 2.1 is incompatible with 1.4. That
+means, a key created with GnuPG 2.1 is not visible with 1.4.
+
+@item
+GnuPG 2.1 uses a fixed address for the Unix domain socket used to
+communicate with gpg-agent. The @code{GPG_AGENT_INFO} environment
+variable, which is used by GnuPG 2.0 and 1.4, is ignored. That means,
+if your system has both GnuPG 2.1 and 1.4, the gpg command from GnuPG
+1.4 is not able to use gpg-agent provided by 2.1 (at least out of box).q
+
+@item
+GnuPG 2.1 (2.1.5 or later) has a mechanism to direct the Pinentry
+password prompt to the Emacs minibuffer@footnote{To enable this
+feature, add @samp{allow-emacs-pinentry} to
+@file{~/.gnupg/gpg-agent.conf} and let gpg-agent reload the
+configuration, with: @samp{gpgconf --reload gpg-agent}}, which would
+be useful when you use Emacs remotely or from a text-only terminal.
+That feature is not available in other versions, and more
+specifically, with 2.0 (as of 2.0.29), there is no way to avoid the
+graphical prompt.
+@end itemize
+
+@node Caching Passphrases, Bug Reports, GnuPG version compatibility, Top
@chapter Caching Passphrases
-Typing passphrases is an irritating task if you frequently open and
+Typing passphrases is a troublesome task if you frequently open and
close the same file. GnuPG and EasyPG Assistant provide mechanisms to
remember your passphrases. However, the configuration is a bit
-confusing since it depends on your GnuPG installation (GnuPG version 1 or
-GnuPG version 2), encryption method (symmetric or public key), and whether or
-not you want to use gpg-agent. Here are some questions:
+confusing since it depends on your GnuPG installation@xref{GnuPG
+version compatibility}, encryption method (symmetric or public key),
+and whether or not you want to use gpg-agent. Here are some
+questions:
@enumerate
-@item Do you use GnuPG version 2 instead of GnuPG version 1?
+@item Do you use GnuPG version 2.1 or 2.0 instead of GnuPG version 1.4?
@item Do you use symmetric encryption rather than public key encryption?
@item Do you want to use gpg-agent?
@end enumerate
@code{epa-file-cache-passphrase-for-symmetric-encryption}.
@xref{Encrypting/decrypting gpg files}.
-@node Bug Reports
+@node Bug Reports, GNU Free Documentation License, Caching Passphrases, Top
@chapter Bug Reports
Bugs and problems with EasyPG Assistant are actively worked on by the
of the @file{ *epg-debug*} buffer. Note that the first letter of the
buffer name is a whitespace.
-@node GNU Free Documentation License
+@node GNU Free Documentation License, Key Index, Bug Reports, Top
@appendix GNU Free Documentation License
@include doclicense.texi
-@node Key Index
+@node Key Index, Function Index, GNU Free Documentation License, Top
@unnumbered Key Index
@printindex ky
-@node Function Index
+@node Function Index, Variable Index, Key Index, Top
@unnumbered Function Index
@printindex fn
-@node Variable Index
+@node Variable Index, , Function Index, Top
@unnumbered Variable Index
@printindex vr
this, and Emacs supports it, then the images will be rescaled down to
fit these criteria.
+@item gnus-article-show-cursor
+@vindex gnus-article-show-cursor
+If non-@code{nil}, display the cursor in the article buffer even when
+the article buffer isn't the current buffer.
@end table
To use this, make sure that you have @code{w3m} and @code{curl}
% Load plain if necessary, i.e., if running under initex.
\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
%
-\def\texinfoversion{2016-02-09.12}
+\def\texinfoversion{2016-02-16.15}
%
% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
% Margin to add to right of even pages, to left of odd pages.
\newdimen\bindingoffset
\newdimen\normaloffset
-\newdimen\pagewidth \newdimen\pageheight
+\newdimen\txipagewidth \newdimen\txipageheight
% Main output routine.
%
% Common context changes for both heading and footing.
% Do this outside of the \shipout so @code etc. will be expanded in
% the headline as they should be, not taken literally (outputting ''code).
- \def\commmonheadfootline{\let\hsize=\pagewidth \texinfochars}
+ \def\commmonheadfootline{\let\hsize=\txipagewidth \texinfochars}
%
% Retrieve the information for the headings from the marks in the page,
% and call Plain TeX's \makeheadline and \makefootline, which use the
\newinsert\margin \dimen\margin=\maxdimen
% Main part of page, including any footnotes
-\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+\def\pagebody#1{\vbox to\txipageheight{\boxmaxdepth=\maxdepth #1}}
{\catcode`\@ =11
\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
% marginal hacks, juha@viisa.uucp (Juha Takala)
% \dimen0 is the vertical size of the group's box.
\dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox
% \dimen2 is how much space is left on the page (more or less).
- \dimen2 = \pageheight \advance\dimen2 by -\pagetotal
+ \dimen2 = \txipageheight \advance\dimen2 by -\pagetotal
% if the group doesn't fit on the current page, and it's a big big
% group, force a page break.
\ifdim \dimen0 > \dimen2
- \ifdim \pagetotal < \vfilllimit\pageheight
+ \ifdim \pagetotal < \vfilllimit\txipageheight
\page
\fi
\fi
\newif\ifpdf
\newif\ifpdfmakepagedest
+%
+% For LuaTeX
+%
+
+\ifx\luatexversion\thisisundefined
+\else
+ % Escape PDF strings UTF-8 to UTF-16
+ \begingroup
+ \catcode`\%=12
+ \directlua{
+ function UTF16oct(str)
+ tex.sprint(string.char(0x5c) .. '376' .. string.char(0x5c) .. '377')
+ for c in string.utfvalues(str) do
+ if c < 0x10000 then
+ tex.sprint(
+ string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+ string.char(0x5c) .. string.char(0x25) .. '03o',
+ (c / 256), (c % 256)))
+ else
+ c = c - 0x10000
+ local c_hi = c / 1024 + 0xd800
+ local c_lo = c % 1024 + 0xdc00
+ tex.sprint(
+ string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+ string.char(0x5c) .. string.char(0x25) .. '03o' ..
+ string.char(0x5c) .. string.char(0x25) .. '03o' ..
+ string.char(0x5c) .. string.char(0x25) .. '03o',
+ (c_hi / 256), (c_hi % 256),
+ (c_lo / 256), (c_lo % 256)))
+ end
+ end
+ end
+ }
+ \endgroup
+ \def\pdfescapestring#1{\directlua{UTF16oct('\luaescapestring{#1}')}}
+ \ifnum\luatexversion>84
+ % For LuaTeX >= 0.85
+ \def\pdfdest{\pdfextension dest}
+ \let\pdfoutput\outputmode
+ \def\pdfliteral{\pdfextension literal}
+ \def\pdfcatalog{\pdfextension catalog}
+ \def\pdftexversion{\numexpr\pdffeedback version\relax}
+ \let\pdfximage\saveimageresource
+ \let\pdfrefximage\useimageresource
+ \let\pdflastximage\lastsavedimageresourceindex
+ \def\pdfendlink{\pdfextension endlink\relax}
+ \def\pdfoutline{\pdfextension outline}
+ \def\pdfstartlink{\pdfextension startlink}
+ \def\pdffontattr{\pdfextension fontattr}
+ \def\pdfobj{\pdfextension obj}
+ \def\pdflastobj{\numexpr\pdffeedback lastobj\relax}
+ \let\pdfpagewidth\pagewidth
+ \let\pdfpageheight\pageheight
+ \edef\pdfhorigin{\pdfvariable horigin}
+ \edef\pdfvorigin{\pdfvariable vorigin}
+ \fi
+\fi
+
% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
% can be set). So we test for \relax and 0 as well as being undefined.
\ifx\pdfoutput\thisisundefined
% page number. We could generate a destination for the section
% text in the case where a section has no node, but it doesn't
% seem worth the trouble, since most documents are normally structured.
- \edef\pdfoutlinedest{#3}%
- \ifx\pdfoutlinedest\empty
- \def\pdfoutlinedest{#4}%
- \else
- \txiescapepdf\pdfoutlinedest
- \fi
- %
- % Also escape PDF chars in the display string.
- \edef\pdfoutlinetext{#1}%
- \txiescapepdf\pdfoutlinetext
- %
- \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}%
+ {
+ \ifx\luatexversion\thisisundefined \else
+ \turnoffactive % LuaTeX can use Unicode strings for PDF
+ \fi
+ \edef\pdfoutlinedest{#3}%
+ \ifx\pdfoutlinedest\empty
+ \def\pdfoutlinedest{#4}%
+ \else
+ \txiescapepdf\pdfoutlinedest
+ \fi
+ %
+ % Also escape PDF chars in the display string.
+ \edef\pdfoutlinetext{#1}%
+ \txiescapepdf\pdfoutlinetext
+ %
+ \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}%
+ }
}
%
\def\pdfmakeoutlines{%
]
\special{pdf:docview << /PageMode /UseOutlines >> }
- \special{pdf:tounicode UTF8-UTF16 }
+ \openin 1 uptex.tex % upTeX has UTF8-UTF16 cmap
+ \ifeof 1
+ % upTeX does not exist. To use UTF8-UCS2 cmap.
+ % In this case, non-BMP characters (over U+FFFF) can not be used.
+ \special{pdf:tounicode UTF8-UCS2}
+ \else
+ % upTeX exists. To use UTF8-UTF16 cmap.
+ % Non-BMP characters (over U+FFFF) can be used.
+ \special{pdf:tounicode UTF8-UTF16}
+ \fi
\fi
%
%
% Leave some space for the footline. Hopefully ok to assume
% @evenfooting will not be used by itself.
- \global\advance\pageheight by -12pt
+ \global\advance\txipageheight by -12pt
\global\advance\vsize by -12pt
}
\def\oddheadingmarks{\headingmarks{odd}{heading}}
\def\evenfootingmarks{\headingmarks{even}{footing}}
\def\oddfootingmarks{\headingmarks{odd}{footing}}
-\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1}
+\parseargdef\everyheadingmarks{\headingmarks{even}{heading}{#1}
\headingmarks{odd}{heading}{#1} }
-\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1}
+\parseargdef\everyfootingmarks{\headingmarks{even}{footing}{#1}
\headingmarks{odd}{footing}{#1} }
% #1 = even/odd, #2 = heading/footing, #3 = top/bottom.
\def\headingmarks#1#2#3 {%
% By default, they are off at the start of a document,
% and turned `on' after @end titlepage.
-\def\headings #1 {\csname HEADINGS#1\endcsname}
+\parseargdef\headings{\csname HEADINGS#1\endcsname}
\def\headingsoff{% non-global headings elimination
\evenheadline={\hfil}\evenfootline={\hfil}%
\wd0=\hsize \wd2=\hsize
\vbox{%
\vskip\doublecolumntopgap
- \hbox to\pagewidth{\box0\hfil\box2}}%
+ \hbox to\txipagewidth{\box0\hfil\box2}}%
}
% goal. When TeX sees \eject from below which follows the final
% section, it invokes the new output routine that we've set after
% \balancecolumns below; \onepageout will try to fit the two columns
- % and the final section into the vbox of \pageheight (see
+ % and the final section into the vbox of \txipageheight (see
% \pagebody), causing an overfull box.
%
% Note that glue won't work here, because glue does not exercise the
\fi
}
-\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+\parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname}
\def\CHAPPAGoff{%
\global\let\contentsalignmacro = \chappager
% I don't think this chapter style is supported any more, so I'm not
% updating it with the new noderef stuff. We'll see. --karl, 11aug03.
%
-\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+\parseargdef\setchapterstyle{\csname CHAPF#1\endcsname}
%
\def\unnchfopen #1{%
\chapoddpage
% We want to typeset this text as a normal paragraph, even if the
% footnote reference occurs in (for example) a display environment.
% So reset some parameters.
- \hsize=\pagewidth
+ \hsize=\txipagewidth
\interlinepenalty\interfootnotelinepenalty
\splittopskip\ht\strutbox % top baseline for broken footnotes
\splitmaxdepth\dp\strutbox
\advance\vsize by \topskip
\outervsize = \vsize
\advance\outervsize by 2\topandbottommargin
- \pageheight = \vsize
+ \txipageheight = \vsize
%
\hsize = #2\relax
\outerhsize = \hsize
\advance\outerhsize by 0.5in
- \pagewidth = \hsize
+ \txipagewidth = \hsize
%
\normaloffset = #4\relax
\bindingoffset = #5\relax
@global@let\ = @eatinput%
@catcode`@^^M=13%
@def@c{@fixbackslash@c}%
+ % Definition for the newline at the end of this file.
@def ^^M{@let^^M@secondlinenl}%
- @gdef @secondlinenl{@let^^M@thirdlinenl}%
- @gdef @thirdlinenl{@fixbackslash}%
+ % Definition for a newline in the main Texinfo file.
+ @gdef @secondlinenl{@fixbackslash}%
}}
{@catcode`@^=7 @catcode`@^^M=13%
** Search and Replace
-+++
-*** New user option `search-default-mode'
-specifies the default mode for I-search.
-
+++
*** `isearch' and `query-replace' can now perform character folding in matches.
Isearch does that by default, while `query-replace' will do that if
those composed of multiple characters, as well as many other symbols
like ℀, ℁, ⒜, and ⓐ.
+Character folding is enabled by customizing `search-default-mode' to
+the value `character-fold-to-regexp'. If you want to turn character
+folding off, customize the value of `search-default-mode' to the `nil'
+value. You can also toggle character folding in the middle of a
+search by typing `M-s ''.
+
++++
+*** New user option `search-default-mode'.
+This option specifies the default mode for Isearch. The default
+value, `character-fold-to-regexp' specifies that Isearch should fold
+characters when searching.
+
+++
*** New function `character-fold-to-regexp' can be used
by searching commands to produce a regexp matching anything that
minibuffer instead of a graphical dialog, depending on whether the gpg
command is called from Emacs (i.e., INSIDE_EMACS environment variable
is set). This feature requires newer versions of GnuPG (2.1.5 or
-later) and Pinentry (0.9.5 or later).
+later) and Pinentry (0.9.5 or later). To use this feature, add
+"allow-emacs-pinentry" to "~/.gnupg/gpg-agent.conf" and reload the
+configuration with "gpgconf --reload gpg-agent".
+++
** cl-generic.el provides CLOS-style multiple-dispatch generic functions.
# elif ((defined __APPLE__ && defined __MACH__ \
? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \
: __GNUC__) \
- || __HP_cc || __HP_aCC || __IBMC__ || __IBMCPP__ \
- || __ICC || 0x590 <= __SUNPRO_C)
+ || 061200 <= __HP_cc || 061200 <= __HP_aCC \
+ || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__)
# define _Alignas(a) __attribute__ ((__aligned__ (a)))
# elif 1300 <= _MSC_VER
# define _Alignas(a) __declspec (align (a))
(cond ((looking-at "; charging")
(setq battery-status "charging"
battery-status-symbol "+"))
- ((< (string-to-number load-percentage) battery-load-low)
- (setq battery-status "low"
- battery-status-symbol "-"))
((< (string-to-number load-percentage) battery-load-critical)
(setq battery-status "critical"
battery-status-symbol "!"))
+ ((< (string-to-number load-percentage) battery-load-low)
+ (setq battery-status "low"
+ battery-status-symbol "-"))
(t
(setq battery-status "high"
battery-status-symbol "")))
;;; Measures, by François Cardarelli)
;;; All conversions are exact unless otherwise noted.
+;; CODATA values updated February 2016, using 2014 adjustment
+;; http://arxiv.org/pdf/1507.07956.pdf
+
(defvar math-standard-units
'( ;; Length
( m nil "*Meter" )
"31.10347680 g") ;; ESUWM, 1/12 exact value for lbt
( ct "(2/10) g" "Carat" nil
"0.2 g") ;; ESUWM
- ( u "1.660538782*10^(-27) kg" "Unified atomic mass" nil
- "1.660538782 10^-27 kg (*)");;(approx) CODATA
+ ( u "1.660539040*10^(-27) kg" "Unified atomic mass" nil
+ "1.660539040 10^-27 kg (*)");;(approx) CODATA
;; Force
( N "m kg/s^2" "*Newton" )
( C "A s" "Coulomb" )
( Fdy "ech Nav" "Faraday" )
( e "ech" "Elementary charge" )
- ( ech "1.602176487*10^(-19) C" "Elementary charge" nil
- "1.602176487 10^-19 C (*)") ;;(approx) CODATA
+ ( ech "1.6021766208*10^(-19) C" "Elementary charge" nil
+ "1.6021766208 10^-19 C (*)") ;;(approx) CODATA
( V "W/A" "Volt" )
( ohm "V/A" "Ohm" )
( Ω "ohm" "Ohm" )
;; Other physical quantities
;; The values are from CODATA, and are approximate.
- ( h "6.62606896*10^(-34) J s" "*Planck's constant" nil
- "6.62606896 10^-34 J s (*)")
+ ( h "6.626070040*10^(-34) J s" "*Planck's constant" nil
+ "6.626070040 10^-34 J s (*)")
( hbar "h / (2 pi)" "Planck's constant" ) ;; Exact
( mu0 "4 pi 10^(-7) H/m" "Permeability of vacuum") ;; Exact
( μ0 "mu0" "Permeability of vacuum") ;; Exact
( eps0 "1 / (mu0 c^2)" "Permittivity of vacuum" )
( ε0 "eps0" "Permittivity of vacuum" )
- ( G "6.67428*10^(-11) m^3/(kg s^2)" "Gravitational constant" nil
- "6.67428 10^-11 m^3/(kg s^2) (*)")
- ( Nav "6.02214179*10^(23) / mol" "Avogadro's constant" nil
- "6.02214179 10^23 / mol (*)")
- ( me "9.10938215*10^(-31) kg" "Electron rest mass" nil
- "9.10938215 10^-31 kg (*)")
- ( mp "1.672621637*10^(-27) kg" "Proton rest mass" nil
- "1.672621637 10^-27 kg (*)")
- ( mn "1.674927211*10^(-27) kg" "Neutron rest mass" nil
- "1.674927211 10^-27 kg (*)")
- ( mmu "1.88353130*10^(-28) kg" "Muon rest mass" nil
- "1.88353130 10^-28 kg (*)")
+ ( G "6.67408*10^(-11) m^3/(kg s^2)" "Gravitational constant" nil
+ "6.67408 10^-11 m^3/(kg s^2) (*)")
+ ( Nav "6.022140857*10^(23) / mol" "Avogadro's constant" nil
+ "6.022140857 10^23 / mol (*)")
+ ( me "9.10938356*10^(-31) kg" "Electron rest mass" nil
+ "9.10938356 10^-31 kg (*)")
+ ( mp "1.672621898*10^(-27) kg" "Proton rest mass" nil
+ "1.672621898 10^-27 kg (*)")
+ ( mn "1.674927471*10^(-27) kg" "Neutron rest mass" nil
+ "1.674927471 10^-27 kg (*)")
+ ( mmu "1.883531594*10^(-28) kg" "Muon rest mass" nil
+ "1.883531594 10^-28 kg (*)")
( mμ "mmu" "Muon rest mass" nil
- "1.88353130 10^-28 kg (*)")
- ( Ryd "10973731.568527 /m" "Rydberg's constant" nil
- "10973731.568527 /m (*)")
- ( k "1.3806504*10^(-23) J/K" "Boltzmann's constant" nil
- "1.3806504 10^-23 J/K (*)")
- ( alpha "7.2973525376*10^(-3)" "Fine structure constant" nil
- "7.2973525376 10^-3 (*)")
+ "1.883531594 10^-28 kg (*)")
+ ( Ryd "10973731.568508 /m" "Rydberg's constant" nil
+ "10973731.568508 /m (*)")
+ ( k "1.38064852*10^(-23) J/K" "Boltzmann's constant" nil
+ "1.38064852 10^-23 J/K (*)")
+ ( sigma "5.670367*10^(-8) W/(m^2 K^4)" "Stefan-Boltzmann constant" nil
+ "5.670367 10^-8 W/(m^2 K^4) (*)")
+ ( σ "sigma" "Stefan-Boltzmann constant" nil
+ "5.670367 10^-8 W/(m^2 K^4) (*)")
+ ( alpha "7.2973525664*10^(-3)" "Fine structure constant" nil
+ "7.2973525664 10^-3 (*)")
( α "alpha" "Fine structure constant" nil
- "7.2973525376 10^-3 (*)")
- ( muB "927.400915*10^(-26) J/T" "Bohr magneton" nil
- "927.400915 10^-26 J/T (*)")
- ( muN "5.05078324*10^(-27) J/T" "Nuclear magneton" nil
- "5.05078324 10^-27 J/T (*)")
- ( mue "-928.476377*10^(-26) J/T" "Electron magnetic moment" nil
- "-928.476377 10^-26 J/T (*)")
- ( mup "1.410606662*10^(-26) J/T" "Proton magnetic moment" nil
- "1.410606662 10^-26 J/T (*)")
- ( R0 "8.314472 J/(mol K)" "Molar gas constant" nil
- "8.314472 J/(mol K) (*)")
- ( V0 "22.710981*10^(-3) m^3/mol" "Standard volume of ideal gas" nil
- "22.710981 10^-3 m^3/mol (*)")
+ "7.2973525664 10^-3 (*)")
+ ( muB "927.4009994*10^(-26) J/T" "Bohr magneton" nil
+ "927.4009994 10^-26 J/T (*)")
+ ( muN "5.050783699*10^(-27) J/T" "Nuclear magneton" nil
+ "5.050783699 10^-27 J/T (*)")
+ ( mue "-928.4764620*10^(-26) J/T" "Electron magnetic moment" nil
+ "-928.4764620 10^-26 J/T (*)")
+ ( mup "1.4106067873*10^(-26) J/T" "Proton magnetic moment" nil
+ "1.4106067873 10^-26 J/T (*)")
+ ( R0 "8.3144598 J/(mol K)" "Molar gas constant" nil
+ "8.3144598 J/(mol K) (*)")
+ ( V0 "22.710947*10^(-3) m^3/mol" "Standard volume of ideal gas" nil
+ "22.710947 10^-3 m^3/mol (*)")
;; Logarithmic units
( Np nil "*Neper")
( dB "(ln(10)/20) Np" "decibel")))
"TeX point will be `pt' instead of `texpt', for example.\n"
"To avoid conflicts, the unit names for pint and parsec will\n"
"be `pint' and `parsec' instead of `pt' and `pc'."))))
- (view-mode)
+ (special-mode)
(message "Formatting units table...done"))
(setq math-units-table-buffer-valid t)
(let ((oldbuf (current-buffer)))
(mlist (append tmn-array nil))
(tma-array todo-month-abbrev-array)
(mablist (append tma-array nil))
- (yy (and oyear (unless (string= oyear "*")
- (string-to-number oyear))))
- (mm (or (and omonth (unless (string= omonth "*")
+ (yy (and oyear (string-to-number oyear))) ; 0 if year is "*".
+ (mm (or (and omonth (if (string= omonth "*") 13
(string-to-number omonth)))
(1+ (- (length mlist)
(length (or (member omonthname mlist)
(if omonth
(number-to-string mm)
(aref tma-array (1- mm))))))
- (let ((yy (string-to-number year)) ; 0 if year is "*".
- ;; When mm is 13 (corresponding to "*" as value
- ;; of month), this raises an args-out-of-range
- ;; error in calendar-last-day-of-month, so use 1
- ;; (corresponding to January) to get 31 days.
- (mm (if (= mm 13) 1 mm)))
+ ;; Since the number corresponding to the arbitrary
+ ;; month name "*" is out of the range of
+ ;; calendar-last-day-of-month, set it to 1
+ ;; (corresponding to January) to allow 31 days.
+ (let ((mm (if (= mm 13) 1 mm)))
(if (> (string-to-number day)
(calendar-last-day-of-month mm yy))
(user-error "%s %s does not have %s days"
monthname omonthname
day (cond
((not current-prefix-arg)
- (todo-read-date 'day mm oyear))
+ (todo-read-date 'day mm yy))
((string= oday "*")
(user-error "Cannot increment *"))
((or (string= omonth "*") (string= omonthname "*"))
(and day (setq day (if (eq day '*)
(symbol-name '*)
(number-to-string day))))
- (and month (setq month (if (eq month '*)
+ (and month (setq month (if (= month 13)
(symbol-name '*)
(number-to-string month))))
(if arg
(when (semanticdb-live-p obj)
(when (semanticdb-in-buffer-p obj)
(with-current-buffer (semanticdb-in-buffer-p obj)
-
- ;; Make sure all our tag lists are up to date.
- (semantic-fetch-tags)
-
- ;; Try to get an accurate unmatched syntax table.
- (when (and (boundp semantic-show-unmatched-syntax-mode)
- semantic-show-unmatched-syntax-mode)
- ;; Only do this if the user runs unmatched syntax
- ;; mode display entries.
- (oset obj unmatched-syntax
- (semantic-show-unmatched-lex-tokens-fetch))
- )
-
- ;; Make sure pointmax is up to date
- (oset obj pointmax (point-max))
- ))
+ (save-excursion
+ ;; Make sure all our tag lists are up to date.
+ (semantic-fetch-tags)
+
+ ;; Try to get an accurate unmatched syntax table.
+ (when (and (boundp semantic-show-unmatched-syntax-mode)
+ semantic-show-unmatched-syntax-mode)
+ ;; Only do this if the user runs unmatched syntax
+ ;; mode display entries.
+ (oset obj unmatched-syntax
+ (semantic-show-unmatched-lex-tokens-fetch))
+ )
+
+ ;; Make sure pointmax is up to date
+ (oset obj pointmax (point-max))
+ )))
;; Make sure that the file size and other attributes are
;; up to date.
(semanticdb-kill-hook kill-buffer-hook)
(semanticdb-kill-hook change-major-mode-hook) ;; Not really a kill, but we need the same effect.
(semanticdb-kill-emacs-hook kill-emacs-hook)
- (semanticdb-save-all-db-idle auto-save-hook)
)
"List of hooks and values to add/remove when configuring semanticdb.")
MEMBERS should be an alist of the form ((NAME WIDGET)...) where
NAME is a symbol and WIDGET is a widget for editing that symbol.
Useful widgets are `custom-variable' for editing variables,
-`custom-face' for edit faces, and `custom-group' for editing groups.
+`custom-face' for editing faces, and `custom-group' for editing groups.
The remaining arguments should have the form
(doc-view-start-process "odf->pdf" doc-view-odf->pdf-converter-program
(list
(concat "-env:UserInstallation=file://"
+ ;; The URL must be
+ ;; file:///C:/tmp/dir on Windows.
+ ;; https://wiki.documentfoundation.org/UserProfile.
+ (when (eq system-type 'windows-nt)
+ "/")
tmp-user-install-dir)
"--headless" "--convert-to" "pdf"
"--outdir" (doc-view--current-cache-dir) odf)
(cl--generic-prefill-dispatchers 0 (eql nil))
(cl--generic-prefill-dispatchers window-system (eql nil))
+(cl--generic-prefill-dispatchers (terminal-parameter nil 'xterm--get-selection)
+ (eql nil))
+(cl--generic-prefill-dispatchers (terminal-parameter nil 'xterm--set-selection)
+ (eql nil))
;;; Support for cl-defstructs specializers.
(defvar package--downloads-in-progress nil
"List of in-progress asynchronous downloads.")
-(declare-function epg-check-configuration "epg-config"
- (config &optional minimum-version))
-(declare-function epg-configuration "epg-config" ())
+(declare-function epg-find-configuration "epg-config"
+ (protocol &optional force))
(declare-function epg-import-keys-from-file "epg" (context keys))
;;;###autoload
(let ((default-keyring (expand-file-name "package-keyring.gpg"
data-directory))
(inhibit-message async))
+ (if (get 'package-check-signature 'saved-value)
+ (when package-check-signature
+ (epg-find-configuration 'OpenPGP))
+ (setq package-check-signature
+ (if (epg-find-configuration 'OpenPGP)
+ 'allow-unsigned)))
(when (and package-check-signature (file-exists-p default-keyring))
(condition-case-unless-debug error
- (progn
- (epg-check-configuration (epg-configuration))
- (package-import-keyring default-keyring))
+ (package-import-keyring default-keyring)
(error (message "Cannot import default keyring: %S" (cdr error))))))
(package--download-and-read-archives async))
;;; Code:
+(eval-when-compile (require 'cl-lib))
+
(defconst epg-package-name "epg"
"Name of this package.")
(defconst epg-gpg-minimum-version "1.4.3")
+(defconst epg-config--program-alist
+ '((OpenPGP
+ epg-gpg-program
+ epg-config--make-gpg-configuration
+ ("gpg2" . "2.1.6") ("gpg" . "1.4.3"))
+ (CMS
+ epg-gpgsm-program
+ epg-config--make-gpgsm-configuration
+ ("gpgsm" . "2.0.4")))
+ "Alist used to obtain the usable configuration of executables.
+The first element of each entry is protocol symbol, which is
+either `OpenPGP' or `CMS'. The second element is a symbol where
+the executable name is remembered. The third element is a
+function which constructs a configuration object (actually a
+plist). The rest of the entry is an alist mapping executable
+names to the minimum required version suitable for the use with
+Emacs.")
+
+(defvar epg--configurations nil)
+
;;;###autoload
-(defun epg-configuration ()
- "Return a list of internal configuration parameters of `epg-gpg-program'."
+(defun epg-find-configuration (protocol &optional force)
+ "Find or create a usable configuration to handle PROTOCOL.
+This function first looks at the existing configuration found by
+the previous invocation of this function, unless FORCE is non-nil.
+
+Then it walks through `epg-config--program-alist'. If
+`epg-gpg-program' or `epg-gpgsm-program' is already set with
+custom, use it. Otherwise, it tries the programs listed in the
+entry until the version requirement is met."
+ (let ((entry (assq protocol epg-config--program-alist)))
+ (unless entry
+ (error "Unknown protocol %S" protocol))
+ (cl-destructuring-bind (symbol constructor . alist)
+ (cdr entry)
+ (or (and (not force) (alist-get protocol epg--configurations))
+ ;; If the executable value is already set with M-x
+ ;; customize, use it without checking.
+ (if (get symbol 'saved-value)
+ (let ((configuration (funcall constructor (symbol-value symbol))))
+ (push (cons protocol configuration) epg--configurations)
+ configuration)
+ (catch 'found
+ (dolist (program-version alist)
+ (let ((executable (executable-find (car program-version))))
+ (when executable
+ (let ((configuration
+ (funcall constructor executable)))
+ (when (ignore-errors
+ (epg-check-configuration configuration
+ (cdr program-version))
+ t)
+ (push (cons protocol configuration) epg--configurations)
+ (throw 'found configuration))))))))))))
+
+;; Create an `epg-configuration' object for `gpg', using PROGRAM.
+(defun epg-config--make-gpg-configuration (program)
(let (config groups type args)
(with-temp-buffer
- (apply #'call-process epg-gpg-program nil (list t nil) nil
+ (apply #'call-process program nil (list t nil) nil
(append (if epg-gpg-home-directory
(list "--homedir" epg-gpg-home-directory))
'("--with-colons" "--list-config")))
type args))))
(t
(setq config (cons (cons type args) config))))))
+ (push (cons 'program program) config)
(if groups
(cons (cons 'groups groups) config)
config)))
+;; Create an `epg-configuration' object for `gpgsm', using PROGRAM.
+(defun epg-config--make-gpgsm-configuration (program)
+ (with-temp-buffer
+ (call-process program nil (list t nil) nil "--version")
+ (goto-char (point-min))
+ (when (looking-at "\\S-+ (")
+ (goto-char (match-end 0))
+ (backward-char)
+ (forward-sexp)
+ (skip-syntax-forward "-" (point-at-eol))
+ (list (cons 'program program)
+ (cons 'version (buffer-substring (point) (point-at-eol)))))))
+
+;;;###autoload
+(defun epg-configuration ()
+ "Return a list of internal configuration parameters of `epg-gpg-program'."
+ (declare (obsolete epg-find-configuration "25.1"))
+ (epg-config--make-gpg-configuration epg-gpg-program))
+
(defun epg-config--parse-version (string)
(let ((index 0)
version)
compress-algorithm
&aux
(program
- (pcase protocol
- (`OpenPGP epg-gpg-program)
- (`CMS epg-gpgsm-program)
- (_ (signal 'epg-error
- (list "unknown protocol" protocol)))))))
+ (let ((configuration (epg-find-configuration protocol)))
+ (unless configuration
+ (signal 'epg-error
+ (list "no usable configuration" protocol)))
+ (alist-get 'program configuration)))))
(:copier nil)
(:predicate nil))
protocol
;;; Code:
+(eval-when-compile
+ (require 'cl))
+
(defconst file-notify--library
(cond
((featurep 'inotify) 'inotify)
DESCRIPTOR should be an object returned by `file-notify-add-watch'.
If it is registered in `file-notify-descriptors', a stopped event is sent."
(let* ((desc (if (consp descriptor) (car descriptor) descriptor))
- (file (if (consp descriptor) (cdr descriptor)))
(registered (gethash desc file-notify-descriptors))
+ (file (if (consp descriptor) (cdr descriptor) (caadr registered)))
(dir (car registered)))
(when (consp registered)
;; Send `stopped' event.
- (dolist (entry (cdr registered))
- (funcall (cdr entry)
- `(,descriptor stopped
- ,(or (and (stringp (car entry))
- (expand-file-name (car entry) dir))
- dir))))
+ (funcall
+ (cdr (assoc file (cdr registered)))
+ `(,descriptor stopped ,(if file (expand-file-name file dir) dir)))
;; Modify `file-notify-descriptors'.
(if (not file)
"A pending file notification events for a future `renamed' action.
It is a form ((DESCRIPTOR ACTION FILE [FILE1-OR-COOKIE]) CALLBACK).")
+(defun file-notify--event-watched-file (event)
+ "Return file or directory being watched.
+Could be different from the directory watched by the backend library."
+ (let* ((desc (if (consp (car event)) (caar event) (car event)))
+ (registered (gethash desc file-notify-descriptors))
+ (file (if (consp (car event)) (cdar event) (caadr registered)))
+ (dir (car registered)))
+ (if file (expand-file-name file dir) dir)))
+
(defun file-notify--event-file-name (event)
"Return file name of file notification event, or nil."
(directory-file-name
(funcall (cadr pending-event) (car pending-event))
(setq pending-event nil))
- ;; Check for stopped.
- (setq
- stopped
- (or
- stopped
- (and
- (memq action '(deleted renamed))
- (= (length (cdr registered)) 1)
- ;; Not, when a file is backed up.
- (not (and (stringp file1) (backup-file-name-p file1)))
- (or
- ;; Watched file or directory is concerned.
- (string-equal
- (file-name-nondirectory file)
- (file-name-nondirectory (car registered)))
- ;; File inside a watched directory is concerned.
- (string-equal
- (file-name-nondirectory file)
- (car (cadr registered)))))))
-
;; Apply callback.
(when (and action
(or
(nth 0 entry) (file-name-nondirectory file1)))))
;;(message
;;"file-notify-callback %S %S %S %S %S"
- ;;(file-notify--descriptor desc file) action file file1 registered)
+ ;;(file-notify--descriptor desc (car entry))
+ ;;action file file1 registered)
(if file1
(funcall
callback
- `(,(file-notify--descriptor desc file) ,action ,file ,file1))
+ `(,(file-notify--descriptor desc (car entry))
+ ,action ,file ,file1))
(funcall
callback
- `(,(file-notify--descriptor desc file) ,action ,file)))))
-
- ;; Modify `file-notify-descriptors'.
- (when stopped
- (file-notify-rm-watch (file-notify--descriptor desc file))))))
+ `(,(file-notify--descriptor desc (car entry)) ,action ,file))))
+
+ ;; Send `stopped' event.
+ (when (and (memq action '(deleted renamed))
+ ;; Not, when a file is backed up.
+ (not (and (stringp file1) (backup-file-name-p file1)))
+ ;; Watched file or directory is concerned.
+ (string-equal file (file-notify--event-watched-file event)))
+ (file-notify-rm-watch (file-notify--descriptor desc (car entry))))))))
;; `kqueue', `gfilenotify' and `w32notify' return a unique descriptor
;; for every `file-notify-add-watch', while `inotify' returns a unique
(item :tag "never" nil)
(sexp :tag "once" :format "%t\n" :value t)))
+(defcustom gnus-article-show-cursor nil
+ "If non-nil, show the cursor in the Article buffer even when not selected."
+ :version "25.1"
+ :group 'gnus-article
+ :type 'bool)
+
(defcustom gnus-saved-headers gnus-visible-headers
"Headers to keep if `gnus-save-all-headers' is nil.
If `gnus-save-all-headers' is non-nil, this variable will be ignored.
(set (make-local-variable 'nobreak-char-display) nil)
;; Enable `gnus-article-remove-images' to delete images shr.el renders.
(set (make-local-variable 'shr-put-image-function) 'gnus-shr-put-image)
- (setq cursor-in-non-selected-windows nil)
+ (unless gnus-article-show-cursor
+ (setq cursor-in-non-selected-windows nil))
(gnus-set-default-directory)
(buffer-disable-undo)
(setq buffer-read-only t
(substring-no-properties lib-name 0 -1)
lib-name)
file-name))
- ;; The next three forms are from `find-source-lisp-file'.
(src-file (locate-library file-name t nil 'readable)))
(and src-file (file-readable-p src-file) src-file))))))
(condition-case nil
(decode-coding-region (point) (point-max) encode)
(coding-system-error nil))
+ (save-excursion
+ ;; Remove CRLF before parsing.
+ (while (re-search-forward "\r$" nil t)
+ (replace-match "" t t)))
(libxml-parse-html-region (point) (point-max))))))
(source (and (null document)
(buffer-substring (point) (point-max)))))
(defun eww-toggle-fonts ()
"Toggle whether to use monospaced or font-enabled layouts."
(interactive)
- (message "Fonts are now %s"
- (if (setq shr-use-fonts (not shr-use-fonts))
- "on"
- "off"))
- (eww-reload))
+ (setq shr-use-fonts (not shr-use-fonts))
+ (eww-reload)
+ (message "Proportional fonts are now %s"
+ (if shr-use-fonts "on" "off")))
(defun eww-toggle-colors ()
"Toggle whether to use HTML-specified colors or not."
;; This package allows GnuPG passphrase to be prompted through the
;; minibuffer instead of graphical dialog.
;;
-;; To use, add allow-emacs-pinentry to ~/.gnupg/gpg-agent.conf, and
+;; To use, add "allow-emacs-pinentry" to "~/.gnupg/gpg-agent.conf",
+;; reload the configuration with "gpgconf --reload gpg-agent", and
;; start the server with M-x pinentry-start.
;;
;; The actual communication path between the relevant components is
;;; Code:
+(eval-when-compile (require 'cl-lib))
+
(defgroup pinentry nil
"The Pinentry server"
:version "25.1"
(ignore-errors
(let (delete-by-moving-to-trash)
(delete-file server-file)))
- (setq pinentry--server-process
- (make-network-process
- :name "pinentry"
- :server t
- :noquery t
- :sentinel #'pinentry--process-sentinel
- :filter #'pinentry--process-filter
- :coding 'no-conversion
- :family 'local
- :service server-file))
- (process-put pinentry--server-process :server-file server-file))))
+ (cl-letf (((default-file-modes) ?\700))
+ (setq pinentry--server-process
+ (make-network-process
+ :name "pinentry"
+ :server t
+ :noquery t
+ :sentinel #'pinentry--process-sentinel
+ :filter #'pinentry--process-filter
+ :coding 'no-conversion
+ :family 'local
+ :service server-file))
+ (process-put pinentry--server-process :server-file server-file)))))
(defun pinentry-stop ()
"Stop a Pinentry service."
;; pair element into an open paren element. Doing that would mean that the
;; new open paren wouldn't have the required preceding paren pair element.
;;
- ;; This function is called from c-after-change.
+ ;; This function is called from c-before-change.
;; The caches of non-literals:
;; Note that we use "<=" for the possibility of the second char of a two-char
;; below `here'. To maintain its consistency, we may need to insert a new
;; brace pair.
(let ((here-bol (c-point 'bol here))
- too-high-pa ; recorded {/(/[ next above here, or nil.
+ too-high-pa ; recorded {/(/[ next above or just below here, or nil.
dropped-cons ; was the last removed element a brace pair?
pa)
;; The easy bit - knock over-the-top bits off `c-state-cache'.
;; Do we need to add in an earlier brace pair, having lopped one off?
(if (and dropped-cons
- (< too-high-pa (+ here c-state-cache-too-far)))
+ (<= too-high-pa here))
(c-append-lower-brace-pair-to-state-cache too-high-pa here here-bol))
(setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
(c-state-get-min-scan-pos)))))
(set-buffer (marker-buffer marker))
(xref--goto-char marker)))
-(defun xref--pop-to-location (item &optional window)
+(defun xref--pop-to-location (item &optional action)
"Go to the location of ITEM and display the buffer.
-WINDOW controls how the buffer is displayed:
+ACTION controls how the buffer is displayed:
nil -- switch-to-buffer
`window' -- pop-to-buffer (other window)
- `frame' -- pop-to-buffer (other frame)"
+ `frame' -- pop-to-buffer (other frame)
+If SELECT is non-nil, select the target window."
(let* ((marker (save-excursion
(xref-location-marker (xref-item-location item))))
(buf (marker-buffer marker)))
- (cl-ecase window
+ (cl-ecase action
((nil) (switch-to-buffer buf))
(window (pop-to-buffer buf t))
(frame (let ((pop-up-frames t)) (pop-to-buffer buf t))))
;; The xref buffer is used to display a set of xrefs.
-(defvar-local xref--display-history nil
- "List of pairs (BUFFER . WINDOW), for temporarily displayed buffers.")
-
-(defun xref--save-to-history (buf win)
- (let ((restore (window-parameter win 'quit-restore)))
- ;; Save the new entry if the window displayed another buffer
- ;; previously.
- (when (and restore (not (eq (car restore) 'same)))
- (push (cons buf win) xref--display-history))))
-
-(defun xref--display-position (pos other-window buf)
- ;; Show the location, but don't hijack focus.
- (let ((xref-buf (current-buffer)))
- (with-selected-window (display-buffer buf other-window)
+(defmacro xref--with-dedicated-window (&rest body)
+ `(let* ((xref-w (get-buffer-window xref-buffer-name))
+ (xref-w-dedicated (window-dedicated-p xref-w)))
+ (unwind-protect
+ (progn
+ (when xref-w
+ (set-window-dedicated-p xref-w 'soft))
+ ,@body)
+ (when xref-w
+ (set-window-dedicated-p xref-w xref-w-dedicated)))))
+
+(defun xref--show-pos-in-buf (pos buf select)
+ (let ((xref-buf (current-buffer))
+ win)
+ (with-selected-window
+ (xref--with-dedicated-window
+ (display-buffer buf))
(xref--goto-char pos)
(run-hooks 'xref-after-jump-hook)
- (let ((buf (current-buffer))
- (win (selected-window)))
+ (let ((buf (current-buffer)))
+ (setq win (selected-window))
(with-current-buffer xref-buf
- (setq-local other-window-scroll-buffer buf)
- (xref--save-to-history buf win))))))
+ (setq-local other-window-scroll-buffer buf))))
+ (when select
+ (select-window win))))
-(defun xref--show-location (location)
+(defun xref--show-location (location &optional select)
(condition-case err
(let* ((marker (xref-location-marker location))
(buf (marker-buffer marker)))
- (xref--display-position marker t buf))
+ (xref--show-pos-in-buf marker buf select))
(user-error (message (error-message-string err)))))
(defun xref-show-location-at-point ()
- "Display the source of xref at point in the other window, if any."
+ "Display the source of xref at point in the appropriate window, if any."
(interactive)
(let* ((xref (xref--item-at-point))
(xref--current-item xref))
(when xref
- (xref--show-location (xref-item-location xref)))))
+ ;; Try to avoid the window the current xref buffer was
+ ;; originally created from.
+ (if (window-live-p xref--window)
+ (with-selected-window xref--window
+ (xref--show-location (xref-item-location xref)))
+ (xref--show-location (xref-item-location xref))))))
(defun xref-next-line ()
- "Move to the next xref and display its source in the other window."
+ "Move to the next xref and display its source in the appropriate window."
(interactive)
(xref--search-property 'xref-item)
(xref-show-location-at-point))
(defun xref-prev-line ()
- "Move to the previous xref and display its source in the other window."
+ "Move to the previous xref and display its source in the appropriate window."
(interactive)
(xref--search-property 'xref-item t)
(xref-show-location-at-point))
(get-text-property (point) 'xref-item)))
(defvar-local xref--window nil
- "ACTION argument to call `display-buffer' with.")
+ "The original window this xref buffer was created from.")
(defun xref-goto-xref ()
- "Jump to the xref on the current line and bury the xref buffer."
+ "Jump to the xref on the current line and select its window."
(interactive)
(let ((xref (or (xref--item-at-point)
- (user-error "No reference at point")))
- (window xref--window))
- (xref-quit)
- (xref--pop-to-location xref window)))
+ (user-error "No reference at point"))))
+ (xref--show-location (xref-item-location xref) t)))
(defun xref-query-replace-in-results (from to)
"Perform interactive replacement of FROM with TO in all displayed xrefs.
current-beg (car pair)
current-end (cdr pair)
current-buf (marker-buffer current-beg))
- (pop-to-buffer current-buf)
+ (xref--with-dedicated-window
+ (pop-to-buffer current-buf))
(goto-char current-beg)
(when (re-search-forward from current-end noerror)
(setq found t)))
(defvar xref--xref-buffer-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map [remap quit-window] #'xref-quit)
(define-key map (kbd "n") #'xref-next-line)
(define-key map (kbd "p") #'xref-prev-line)
(define-key map (kbd "r") #'xref-query-replace-in-results)
(dotimes (_ n)
(setq xref (xref--search-property 'xref-item backward)))
(cond (xref
- (xref--pop-to-location xref))
+ (xref--show-location (xref-item-location xref) t))
(t
(error "No %s xref" (if backward "previous" "next"))))))
-(defun xref-quit (&optional kill)
- "Bury temporarily displayed buffers, then quit the current window.
-
-If KILL is non-nil, also kill the current buffer.
-
-The buffers that the user has otherwise interacted with in the
-meantime are preserved."
- (interactive "P")
- (let ((window (selected-window))
- (history xref--display-history))
- (setq xref--display-history nil)
- (pcase-dolist (`(,buf . ,win) history)
- (when (and (window-live-p win)
- (eq buf (window-buffer win)))
- (quit-window nil win)))
- (quit-window kill window)))
-
(defconst xref-buffer-name "*xref*"
"The name of the buffer to show xrefs.")
(defvar xref--read-pattern-history nil)
-(defun xref--show-xrefs (xrefs window &optional always-show-list)
+(defun xref--show-xrefs (xrefs display-action &optional always-show-list)
(cond
((and (not (cdr xrefs)) (not always-show-list))
(xref-push-marker-stack)
- (xref--pop-to-location (car xrefs) window))
+ (xref--pop-to-location (car xrefs) display-action))
(t
(xref-push-marker-stack)
(funcall xref-show-xrefs-function xrefs
- `((window . ,window))))))
+ `((window . ,(selected-window)))))))
(defun xref--prompt-p (command)
(or (eq xref-prompt-for-identifier t)
\f
;;; Commands
-(defun xref--find-xrefs (input kind arg window)
+(defun xref--find-xrefs (input kind arg display-action)
(let ((xrefs (funcall (intern (format "xref-backend-%s" kind))
(xref-find-backend)
arg)))
(unless xrefs
(user-error "No %s found for: %s" (symbol-name kind) input))
- (xref--show-xrefs xrefs window)))
+ (xref--show-xrefs xrefs display-action)))
-(defun xref--find-definitions (id window)
- (xref--find-xrefs id 'definitions id window))
+(defun xref--find-definitions (id display-action)
+ (xref--find-xrefs id 'definitions id display-action))
;;;###autoload
(defun xref-find-definitions (identifier)
(defcustom time-stamp-time-zone nil
"The time zone to be used by \\[time-stamp].
-Its format is that of the ZONE argument of the `format-time-string' function,"
+Its format is that of the ZONE argument of the `format-time-string' function."
:type '(choice (const :tag "Emacs local time" nil)
(const :tag "Universal Time" t)
(const :tag "system wall clock time" wall)
(setq ignore 'preserved)
(setq right first-right)
(while (and right
- (or (window-size-fixed-p right horizontal 'preserved))
- (<= (window-size right horizontal t)
- (window-min-size right horizontal 'preserved t)))
+ (or (window-size-fixed-p right horizontal 'preserved)
+ (<= (window-size right horizontal t)
+ (window-min-size right horizontal 'preserved t))))
(setq right
(or (window-right right)
(progn
(window--resize-mini-window minibuffer-window (- delta)))
((window--resizable-p nil delta horizontal)
(window-resize nil delta horizontal))
+ ((window--resizable-p nil delta horizontal 'preserved)
+ (window-resize nil delta horizontal 'preserved))
+ ((eq this-command 'enlarge-window)
+ (user-error "Cannot enlarge selected window"))
(t
- (window-resize
- nil (if (> delta 0)
- (window-max-delta nil horizontal)
- (- (window-min-delta nil horizontal)))
- horizontal)))))
+ (error "Cannot enlarge selected window")))))
(defun shrink-window (delta &optional horizontal)
"Make the selected window DELTA lines smaller.
(window--resize-mini-window minibuffer-window delta))
((window--resizable-p nil (- delta) horizontal)
(window-resize nil (- delta) horizontal))
+ ((window--resizable-p nil (- delta) horizontal 'preserved)
+ (window-resize nil (- delta) horizontal 'preserved))
+ ((eq this-command 'shrink-window)
+ (user-error "Cannot shrink selected window"))
(t
- (window-resize
- nil (if (> delta 0)
- (- (window-min-delta nil horizontal))
- (window-max-delta nil horizontal))
- horizontal)))))
+ (error "Cannot shrink selected window")))))
(defun maximize-window (&optional window)
"Maximize WINDOW.
(setq woman-frame (make-frame)))))
(set-buffer (get-buffer-create bufname))
(condition-case nil
- (display-buffer (current-buffer))
+ (pop-to-buffer-same-window (current-buffer))
(error (pop-to-buffer (current-buffer))))
(buffer-disable-undo)
(setq buffer-read-only nil)
(if (zerop woman-buffer-number)
(let ((buffer (get-buffer (cdr (car woman-buffer-alist)))))
(if buffer
- (display-buffer buffer)
+ (pop-to-buffer-same-window buffer)
;; Delete alist element:
(setq woman-buffer-alist (cdr woman-buffer-alist))
nil))
(let* ((prev-ptr (nthcdr (1- woman-buffer-number) woman-buffer-alist))
(buffer (get-buffer (cdr (car (cdr prev-ptr))))))
(if buffer
- (display-buffer buffer)
+ (pop-to-buffer-same-window buffer)
;; Delete alist element:
(setcdr prev-ptr (cdr (cdr prev-ptr)))
(if (>= woman-buffer-number (length woman-buffer-alist))
-This directory contains files needed to build Emacs on Nextstep-based
-platforms, including GNUstep and Mac OS X (using the Cocoa libraries).
-See the INSTALL file in this directory for compilation instructions.
+ NS -- the Cocoa interface for OS X and compatible systems
+ ---------------------------------------------------------
+
+This directory contains files needed to build Emacs on system based on
+NextStep (NS), including OS X (Mac) and GNUstep, using the Cocoa API.
+
+
+ HISTORY
+
+Up to Emacs 22, the OS X interface was implemented using the C-based
+Carbon API. Starting with Emacs 23, the interface was rewritten in
+Objective-C using the Cocoa API. Meanwhile, the Carbon interface has
+been maintained independently under the name "mac".
+
+
+ OVERVIEW OF COCOA AND OBJECTIVE-C
+
+Cocoa is an API for the Objective-C language, an objective oriented
+superset of C. Anybody with experience with iOS or modern OS X
+application development should feel at home.
+
+A method call in Objective-C differs from most other languages in the
+fact that it doesn't have a normal name. Instead, the method name is
+made up of the name of each parameter. An exception to this rule are
+methods without parameters.
+
+The following calls a method in the object `anObject'.
+
+ [anObject alpha:1 beta:2 gamma:3];
+
+Classes are declared like the following:
+
+ @interface AClassName
+ {
+ // A class method.
+ + (TYPE)name1:(TYPE)param1
+
+ // An object method.
+ - (TYPE)name1:(TYPE)param1 name2:(TYPE)param2;
+ }
+ @end
+
+
+ GUIDELINES
+
+* Adhere the to the FSF philosophy that a feature in GNU software
+ should not only be available on non-free systems.
+
+* People with varying Cocoa and Objective-C skills will read and
+ modify the NS code over a long period of time. Keep the code simple
+ and avoid language constructs that makes the code hard to maintain.
+
+* Don't use macros and types intended for the XCode Interface Builder,
+ like `IBAction'.
+
+* The NS interface should work on all version of OS X from 10.6.8
+ (Snow Leopard) to the latest official release.
+
+* Under OS X, it is possible to build Emacs using NS, X11, or console
+ only. A new OS X feature should work in all appropriate builds.
+
+
+ TRACING SUPPORT
+
+The NS interface features a printf-based trace package that prints the
+call tree of selected functions in the Cocoa interface, plus various
+extra information. It can be enabled by uncommenting the line
+defining `NSTRACE_ENABLED' in "nsterm.h". To enable more output,
+uncomment the lines defining symbols starting with `NSTRACE_GROUP'.
+
+
+ GNUSTEP AND OTHER COMPATIBLE SYSTEMS
+
+The NS interface works on system compatible with OS X, for example
+GNUstep. Even though they are less frequently used, this is important
+for a number of reasons:
+
+* It supports the GNUstep project and provides an Emacs with the same
+ look-and-feel as the rest of the system.
+
+* This allows other Emacs developers to test their changes on the NS
+ interface without having access to an OS X machine.
+
+* If a feature in the NS interface work on free systems like GNUstep,
+ this meets the FSF requirement that features in GNU software should
+ not only be available on non-free systems.
+
+
+ SEE ALSO
+
+The src/ns... files contains the C and Objective-C parts.
+
+The lisp/term/ns-win.el file contains the lisp part of the NS
+interface.
+
+The INSTALL file in this directory for compilation instructions.
+
+The WISHLIST file in this directory for a list of ideas for future
+development of the NS interface.
--- /dev/null
+ -*- org -*-
+
+ Wish list for the "NS" OS X Emacs port
+ --------------------------------------
+
+ Note: This document is written using "org-mode", a plain-text
+ format supporting outlines. To expand a heading, press TAB. To
+ expand all headings and subheadings, press S-TAB until Emacs
+ responds "SHOW ALL".
+
+* Introduction
+
+This is a wishlist for future development of the "NS" Emacs user
+interface whose primary use is the official Emacs version on OS X.
+
+This list should be seen as a complement to the bug- and wishlist on
+[[http://debbugs.gnu.org/cgi/pkgreport.cgi?package%3Demacs][debbugs]], the Emacs bug tracker.
+
+* Missing features
+
+This sections contains features found in other official Emacs ports.
+
+** Support for "xwidget"
+
+Emacs 25 has support for "xwidgets", a system to include operating
+system components into an Emacs buffer. The components range from
+simple buttons to "webkit" (effectively, a web browser).
+
+Currently, "xwidget" only works for the "gtk+" framework but it is
+designed to be compatible with multiple Emacs ports.
+
+** Respect `frame-inhibit-implied-resize'
+
+When the variable `frame-inhibit-implied-resize' is non-nil, frames
+should not be resized when operations like changing font or toggling
+the tool bar is performed.
+
+Unfortunately, the tool bar (and possible other operations) always
+resize the frame.
+
+** Support `proced' (implement `process-attributes')
+
+Unfortunately, a user-level process like Emacs does not have the
+privileges to get information about other processes under OS X.
+
+There are other ways to do this:
+
+ 1) Spawn "ps" and parse the output ("ps" has superuser privileges).
+
+ 2) Sign Emacs as part of the distribution process.
+
+ 3) Ask the user to self-sign Emacs, if this feature is of interest.
+
+Anders Lindgren <andlind@gmail.com> has implemented
+`process-attributes' for OS X -- which currently only work when
+running Emacs as root.
+
+[[http://emacsredux.com/blog/2013/05/02/manage-processes-with-proced/][See this article by Bozhidar Batsov for an overview of Proced.]]
+
+** Tooltip properties
+
+Tooltip properties like the background color and font are hard wired,
+even though Emacs allow a user to customize such features.
+
+* New features
+
+This section contains features unique to the NS and/or OS X.
+
+** PressAndHold for writing accented character
+
+On OS X, many application supports the press and hold pattern to
+invoke a menu of accented characters. (See example at [[https://support.apple.com/en-us/HT201586][Apple]].)
+
+Currently, this doesn't work in Emacs.
+
+Note that "ns-win.el" explicitly disables this.
+
+Note: This feature might not be allowed to be implemented until also
+implemented in Emacs for a free system.
+
+** Floating scroll bars
+
+In modern OS X applications, the scroll bar often float over the
+content, and is invisible unless actually used. This makes user
+interface less cluttered and more area could be used to contain text.
+
+With floating scroll bars, the user interface would look like it does
+when they are disabled today. However, they will be made visible when
+a scroll action is initiated, e.g. by putting two fingers on a
+trackpad.
+
+Note: This feature might not be allowed to be implemented until also
+implemented in Emacs for a free system.
+
+* Features from the "mac" port
+
+This section contains features available in the "mac" Emacs port.
+
+As the "mac" port (as of this writing) isn't an official Emacs port,
+it might contain features not following the FSF rule "must exist on
+free systems".
+
+The "mac" port is based on the Emacs 22 C-based Carbon interface. It
+has been maintained in parallel to the official Cocoa-based NS
+interface. The Carbon interface has been enhanced, and a number of the
+features of that interface could be implemented NS.
+
+** Smooth scrolling -- maybe not a good idea
+
+Today, by default, scrolling with a trackpad makes the text move in
+steps of five lines. (Scrolling with SHIFT scrolls one line at a
+time.)
+
+The "mac" port provides smooth, pixel-based, scrolling. This is a very
+popular features. However, there are drawbacks to this method: what
+happens if only a fraction of a line is visible at the top of a
+window, is the partially visible text considered part of the window or
+not? (Technically, what should `window-start' return.)
+
+An alternative would be to make one-line scrolling the default on NS
+(or in Emacs in general).
+
+Note: This feature might not be allowed to be implemented until also
+implemented in Emacs for a free system.
+
+** Mouse gestures
+
+The "mac" port defines the gestures `swipe-left/right/up/down',
+`magnify-up/down', and `rotate-left/right'.
+
+It also binds the magnification commands to change the font
+size. (This should be not be done in a specific interface, instead
+Emacs should do this binding globally.)
+
+Note: This feature might not be allowed to be implemented until also
+implemented in Emacs for a free system.
+
+** Synthesize bold fonts
+
+* Open issues
+
+This section contains issues where there is an ongoing debate.
+
+** Key bindings of CMD and ALT
+
+Currently in the "ns" port, ALT is bound to Meta and CMD is bound to
+Super -- allowing the user to use typical OS X commands like CMD-A to
+mark everything.
+
+Unfortunately, when using an international keyboard, you can't type
+normal characters like "(" etc.
+
+There are many alternative key bindings. One solution is to bind CMD
+to Meta and pass ALT to the system. In fact, this is what Emacs did up
+to, and including, version 22. Also, this is how the "mac" port binds
+the keys.
+
+One could envision asymmetrical variants as well, however, this is
+inappropriate for the default setting.
+
+See the discussion on emacs-devel [[https://lists.gnu.org/archive/html/emacs-devel/2015-12/msg01575.html][part 1]] and [[https://lists.gnu.org/archive/html/emacs-devel/2016-01/msg00008.html][part 2]].
+
+* Bugs
+
+This sections contains a small selection of bugs which are hard to
+fix. For other bugs, see the official bug tracker debbugs.gnu.org.
+
+** Incorrect translation of Super modifier with Ctrl or Meta on OS X
+
+When pressing `M-s-a', Emacs replies "M-s-å is undefined". What
+happened is a mix of Emacs view that Meta and Super has been pressed,
+and OS X view that ALT-a should yield "å".
+
+The bug reports suggests two different patched, unfortunately, none
+work properly. For example:
+
+ Use a Swedish keyboard layout
+
+ (setq ns-alternate-modifier nil)
+
+ "CMD-ALT-9"
+
+Today, this correctly yields that s-] is undefined. With the either
+of the two patches, Emacs responds that s-9 was pressed.
+
+More investigation is needed to fix this problem.
+
+Links:
+- [[http://debbugs.gnu.org/cgi/bugreport.cgi?bug%3D19977][bug#19977]]
+- [[http://debbugs.gnu.org/cgi/bugreport.cgi?bug%3D21330][bug#21330]]
+- [[http://debbugs.gnu.org/cgi/bugreport.cgi?bug%3D21551][bug#21551]]
+
+** Toggline the toolbar in fullheight or maximized modes
+
+The toolbar, in the NS interface, is not considered part of the text
+area. When it is toggled, the Emacs frame change height accordingly.
+
+Unfortunately, this also occurs when the frame is in fullheight or
+maximized modes (N.B. this is not the same as "fullscreen"). The
+effect is that the full frame size either increases (stretching down
+below the lower edge of the screen) or decreases (leaving space
+between the lower edge of the frame and the lower edge of the screen).
+
+A better solution would be for the frame to retain its size,
+i.e. change the text area.
+
+This is related to the `frame-inhibit-implied-resize' issue.
+
+* Internal development features
+
+** Regression test system (or at least a checklist)
+
+Today, after each change to the user interface, Emacs must be manually
+tested. Often, small details are overlooked ("Oh, I didn't test
+toggling the tool-bar in one of the full screen modes, when multiple
+frame were open -- silly me.")
+
+It would be an enormous help if this could be tested automatically.
+Many features are generic, however, the NS interface provides a number
+of unique features.
+
+*** Existing packages
+
+Note that there is a generic UI test named "[[http://debbugs.gnu.org/cgi/bugreport.cgi?bug%3D21415#284][frame-test.el]]". The NS
+interface pass this, with the exception of two toolbar related
+errors.
+
+*** Anders frame test
+
+Anders Lindgren <andlind@gmail.com> has implemented some (very basic)
+tests for full screen, toolbar, and auto-hiding the menu bar.
+
+** Make sure all build variants work
+
+Emacs can be build in a number of different ways. For each feature,
+consider if is really is "NS" specific, or if it should be applied to
+all build versions.
+
+- With the "NS" interface. This is the normal way to build Emacs on
+ OS X.
+
+- With the "X11" interface. On OS X, this is mainly of interest to
+ developers of Emacs to get a "reference" interface implementations.
+ However, it might be of interest for people working remotely, as X11
+ applications can be used over a network connection.
+
+- Console only.
}
else
{
- ptrdiff_t pos_byte = coding->dst_pos_byte;
ptrdiff_t pos = coding->dst_pos;
- ptrdiff_t pos_end = pos + coding->produced_char - 1;
+ ptrdiff_t pos_byte = coding->dst_pos_byte;
+ ptrdiff_t pos_end = pos_byte + coding->produced - 1;
- while (pos < pos_end)
+ while (pos_byte < pos_end)
{
p = BYTE_POS_ADDR (pos_byte);
if (*p == '\r' && p[1] == '\n')
DEFVAR_LISP ("disable-point-adjustment", Vdisable_point_adjustment,
doc: /* If non-nil, suppress point adjustment after executing a command.
-After a command is executed, if point is moved into a region that has
-special properties (e.g. composition, display), we adjust point to
-the boundary of the region. But, when a command sets this variable to
-non-nil, we suppress the point adjustment.
+After a command is executed, if point moved into a region that has
+special properties (e.g. composition, display), Emacs adjusts point to
+the boundary of the region. But when a command binds this variable to
+non-nil, this point adjustment is suppressed.
This variable is set to nil before reading a command, and is checked
just after executing the command. */);
DEFVAR_LISP ("global-disable-point-adjustment",
Vglobal_disable_point_adjustment,
- doc: /* If non-nil, always suppress point adjustment.
+ doc: /* If non-nil, always suppress point adjustments.
-The default value is nil, in which case, point adjustment are
+The default value is nil, in which case point adjustments are
suppressed only after special commands that set
`disable-point-adjustment' (which see) to non-nil. */);
Vglobal_disable_point_adjustment = Qnil;
case charset:
case charset_not:
{
- register unsigned int c;
+ register unsigned int c, corig;
boolean not = (re_opcode_t) *(p - 1) == charset_not;
int len;
}
PREFETCH ();
- c = RE_STRING_CHAR_AND_LENGTH (d, len, target_multibyte);
+ corig = c = RE_STRING_CHAR_AND_LENGTH (d, len, target_multibyte);
if (target_multibyte)
{
int c1;
{
int class_bits = CHARSET_RANGE_TABLE_BITS (&p[-1]);
- if ( (class_bits & BIT_LOWER && ISLOWER (c))
+ if ( (class_bits & BIT_LOWER
+ && (ISLOWER (c)
+ || (corig != c
+ && c == upcase (corig) && ISUPPER(c))))
| (class_bits & BIT_MULTIBYTE)
| (class_bits & BIT_PUNCT && ISPUNCT (c))
| (class_bits & BIT_SPACE && ISSPACE (c))
- | (class_bits & BIT_UPPER && ISUPPER (c))
+ | (class_bits & BIT_UPPER
+ && (ISUPPER (c)
+ || (corig != c
+ && c == downcase (corig) && ISLOWER (c))))
| (class_bits & BIT_WORD && ISWORD (c))
| (class_bits & BIT_ALPHA && ISALPHA (c))
| (class_bits & BIT_ALNUM && ISALNUM (c))
advance, and the buffer is enlarged several times as the data is
decompressed on the fly. */
if (nbytes < MAX_BUFFER_SIZE)
- p = VirtualAlloc (NULL, (nbytes * 2), MEM_RESERVE, PAGE_READWRITE);
+ p = VirtualAlloc (NULL, ROUND_UP (nbytes * 2, get_allocation_unit ()),
+ MEM_RESERVE, PAGE_READWRITE);
/* If it fails, or if the request is above 512MB, try with the
requested size. */
if (p == NULL)
- p = VirtualAlloc (NULL, nbytes, MEM_RESERVE, PAGE_READWRITE);
+ p = VirtualAlloc (NULL, ROUND_UP (nbytes, get_allocation_unit ()),
+ MEM_RESERVE, PAGE_READWRITE);
if (p != NULL)
{
int num;
while (fgets (buf, sizeof (buf), fp) != NULL) {
- if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
+ if (sscanf (buf, "%d %d %d %n", &red, &green, &blue, &num) == 3)
{
#ifdef HAVE_NTGUI
int color = RGB (red, green, blue);
(defvar file-notify--test-tmpfile nil)
(defvar file-notify--test-tmpfile1 nil)
(defvar file-notify--test-desc nil)
+(defvar file-notify--test-desc1 nil)
+(defvar file-notify--test-desc2 nil)
(defvar file-notify--test-results nil)
(defvar file-notify--test-event nil)
(defvar file-notify--test-events nil)
(defun file-notify--test-cleanup ()
"Cleanup after a test."
(file-notify-rm-watch file-notify--test-desc)
+ (file-notify-rm-watch file-notify--test-desc1)
+ (file-notify-rm-watch file-notify--test-desc2)
(ignore-errors
(delete-file (file-newest-backup file-notify--test-tmpfile)))
(setq file-notify--test-tmpfile nil
file-notify--test-tmpfile1 nil
file-notify--test-desc nil
+ file-notify--test-desc1 nil
+ file-notify--test-desc2 nil
file-notify--test-results nil
file-notify--test-events nil)
(when file-notify--test-event
(should (equal (car file-notify--test-event) file-notify--test-desc))
;; Check the file name.
(should
- (or (string-equal (file-notify--event-file-name file-notify--test-event)
- file-notify--test-tmpfile)
- (string-equal (file-notify--event-file-name file-notify--test-event)
- file-notify--test-tmpfile1)
- (string-equal (file-notify--event-file-name file-notify--test-event)
- temporary-file-directory)))
+ (string-prefix-p
+ (file-notify--event-watched-file file-notify--test-event)
+ (file-notify--event-file-name file-notify--test-event)))
;; Check the second file name if exists.
(when (eq (nth 1 file-notify--test-event) 'renamed)
(should
- (or (string-equal (file-notify--event-file1-name file-notify--test-event)
- file-notify--test-tmpfile1)
- (string-equal (file-notify--event-file1-name file-notify--test-event)
- temporary-file-directory)))))
+ (string-prefix-p
+ (file-notify--event-watched-file file-notify--test-event)
+ (file-notify--event-file1-name file-notify--test-event)))))
(defun file-notify--test-event-handler (event)
"Run a test over FILE-NOTIFY--TEST-EVENT.
(unless (string-match
(regexp-quote ".#")
(file-notify--event-file-name file-notify--test-event))
- ;;(message "file-notify--test-event-handler %S" file-notify--test-event)
+ ;;(message "file-notify--test-event-handler result: %s event: %S"
+ ;;(null (ert-test-failed-p result)) file-notify--test-event)
(setq file-notify--test-events
(append file-notify--test-events `(,file-notify--test-event))
file-notify--test-results
events, which represent different possible results. Don't wait
longer than timeout seconds for the events to be delivered."
(declare (indent 1))
- (let ((outer (make-symbol "outer")))
- `(let* ((,outer file-notify--test-events)
- (events (if (consp (car ,events)) ,events (list ,events)))
- (max-length (apply 'max (mapcar 'length events)))
- create-lockfiles)
- ;; Flush pending events.
- (file-notify--wait-for-events
- (file-notify--test-timeout)
- (input-pending-p))
- (let (file-notify--test-events)
- ,@body
- (file-notify--wait-for-events
- ;; More events need more time. Use some fudge factor.
- (* (ceiling max-length 100) (file-notify--test-timeout))
- (= max-length (length file-notify--test-events)))
- ;; One of the possible results shall match.
- (should (file-notify--test-with-events-check events))
- (setq ,outer (append ,outer file-notify--test-events)))
- (setq file-notify--test-events ,outer))))
+ `(let* ((events (if (consp (car ,events)) ,events (list ,events)))
+ (max-length (apply 'max (mapcar 'length events)))
+ create-lockfiles)
+ ;; Flush pending events.
+ (file-notify--wait-for-events
+ (file-notify--test-timeout)
+ (input-pending-p))
+ (setq file-notify--test-events nil
+ file-notify--test-results nil)
+ ,@body
+ (file-notify--wait-for-events
+ ;; More events need more time. Use some fudge factor.
+ (* (ceiling max-length 100) (file-notify--test-timeout))
+ (= max-length (length file-notify--test-events)))
+ ;; Check the result sequence just to make sure that all events
+ ;; are as expected.
+ (dolist (result file-notify--test-results)
+ (when (ert-test-failed-p result)
+ (ert-fail
+ (cadr (ert-test-result-with-condition-condition result)))))
+ ;; One of the possible event sequences shall match.
+ (should (file-notify--test-with-events-check events))))
(ert-deftest file-notify-test02-events ()
"Check file creation/change/removal notifications."
"another text" nil file-notify--test-tmpfile nil 'no-message)
(read-event nil nil file-notify--test-read-event-timeout)
(delete-file file-notify--test-tmpfile))
- ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it.
- (let (file-notify--test-events)
- (file-notify-rm-watch file-notify--test-desc)))
+ (file-notify-rm-watch file-notify--test-desc))
;; Check file change and deletion.
(setq file-notify--test-tmpfile (file-notify--test-make-temp-name))
"another text" nil file-notify--test-tmpfile nil 'no-message)
(read-event nil nil file-notify--test-read-event-timeout)
(delete-file file-notify--test-tmpfile))
- ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it.
- (let (file-notify--test-events)
- (file-notify-rm-watch file-notify--test-desc))
+ (file-notify-rm-watch file-notify--test-desc)
;; Check file creation, change and deletion when watching a
;; directory. There must be a `stopped' event when deleting
"any text" nil file-notify--test-tmpfile nil 'no-message)
(read-event nil nil file-notify--test-read-event-timeout)
(delete-directory temporary-file-directory 'recursive))
- ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it.
- (let (file-notify--test-events)
- (file-notify-rm-watch file-notify--test-desc)))
+ (file-notify-rm-watch file-notify--test-desc))
;; Check copy of files inside a directory.
(let ((temporary-file-directory
(set-file-times file-notify--test-tmpfile '(0 0))
(read-event nil nil file-notify--test-read-event-timeout)
(delete-directory temporary-file-directory 'recursive))
- ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it.
- (let (file-notify--test-events)
- (file-notify-rm-watch file-notify--test-desc)))
+ (file-notify-rm-watch file-notify--test-desc))
;; Check rename of files inside a directory.
(let ((temporary-file-directory
;; After the rename, we won't get events anymore.
(read-event nil nil file-notify--test-read-event-timeout)
(delete-directory temporary-file-directory 'recursive))
- ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it.
- (let (file-notify--test-events)
- (file-notify-rm-watch file-notify--test-desc)))
+ (file-notify-rm-watch file-notify--test-desc))
;; Check attribute change. Does not work for cygwin.
(unless (eq system-type 'cygwin)
(set-file-times file-notify--test-tmpfile '(0 0))
(read-event nil nil file-notify--test-read-event-timeout)
(delete-file file-notify--test-tmpfile))
- ;; `file-notify-rm-watch' fires the `stopped' event. Suppress it.
- (let (file-notify--test-events)
- (file-notify-rm-watch file-notify--test-desc)))
-
- ;; Check the global sequence again just to make sure that
- ;; `file-notify--test-events' has been set correctly.
- (should file-notify--test-results)
- (dolist (result file-notify--test-results)
- (when (ert-test-failed-p result)
- (ert-fail
- (cadr (ert-test-result-with-condition-condition result))))))
+ (file-notify-rm-watch file-notify--test-desc)))
;; Cleanup.
(file-notify--test-cleanup)))
(dotimes (i n)
;; It matters which direction we rename, at least for
;; kqueue. This backend parses directories in alphabetic
- ;; order (x%d before y%d). So we rename both directions.
+ ;; order (x%d before y%d). So we rename into both directions.
(if (zerop (mod i 2))
(progn
(push (expand-file-name (format "x%d" i)) source-file-list)
((or (string-equal (file-notify--test-library) "w32notify")
(file-remote-p temporary-file-directory))
'(changed changed))
+ ;; gfilenotify raises one or two `changed' events
+ ;; randomly, no chance to test. So we accept both cases.
+ ((string-equal "gfilenotify" (file-notify--test-library))
+ '((changed)
+ (changed changed)))
(t '(changed)))
;; There shouldn't be any problem, because the file is kept.
(with-temp-buffer
(file-notify--deftest-remote file-notify-test07-backup
"Check that backup keeps file notification for remote files.")
+(ert-deftest file-notify-test08-watched-file-in-watched-dir ()
+ "Watches a directory and a file in that directory separately.
+Checks that the callbacks are only called with events with
+descriptors that were issued when registering the watches. This
+test caters for the situation in bug#22736 where the callback for
+the directory received events for the file with the descriptor of
+the file watch."
+ :tags '(:expensive-test)
+ (skip-unless (file-notify--test-local-enabled))
+
+ ;; A directory to be watched.
+ (should
+ (setq file-notify--test-tmpfile
+ (make-temp-file "file-notify-test-parent" t)))
+ ;; A file to be watched.
+ (should
+ (setq file-notify--test-tmpfile1
+ (let ((temporary-file-directory file-notify--test-tmpfile))
+ (file-notify--test-make-temp-name))))
+ (write-region "any text" nil file-notify--test-tmpfile1 nil 'no-message)
+ (unwind-protect
+ (cl-flet (;; Directory monitor.
+ (dir-callback (event)
+ (let ((file-notify--test-desc file-notify--test-desc1))
+ (file-notify--test-event-handler event)))
+ ;; File monitor.
+ (file-callback (event)
+ (let ((file-notify--test-desc file-notify--test-desc2))
+ (file-notify--test-event-handler event))))
+ (should
+ (setq file-notify--test-desc1
+ (file-notify-add-watch
+ file-notify--test-tmpfile
+ '(change) #'dir-callback)))
+ (should
+ (setq file-notify--test-desc2
+ (file-notify-add-watch
+ file-notify--test-tmpfile1
+ '(change) #'file-callback)))
+ (should (file-notify-valid-p file-notify--test-desc1))
+ (should (file-notify-valid-p file-notify--test-desc2))
+ (should-not (equal file-notify--test-desc1 file-notify--test-desc2))
+ ;; gfilenotify raises one or two `changed' events randomly in
+ ;; the file monitor, no chance to test.
+ (unless (string-equal "gfilenotify" (file-notify--test-library))
+ (let ((n 100) events)
+ ;; Compute the expected events.
+ (dotimes (_i (/ n 2))
+ (setq events
+ (append
+ (append
+ ;; Directory monitor and file monitor.
+ (cond
+ ;; In the remote case, there are two `changed'
+ ;; events.
+ ((file-remote-p temporary-file-directory)
+ '(changed changed changed changed))
+ ;; The directory monitor in kqueue does not
+ ;; raise any `changed' event. Just the file
+ ;; monitor event is received.
+ ((string-equal (file-notify--test-library) "kqueue")
+ '(changed))
+ ;; Otherwise, both monitors report the
+ ;; `changed' event.
+ (t '(changed changed)))
+ ;; Just the directory monitor.
+ (cond
+ ;; In kqueue, there is an additional `changed'
+ ;; event. Why?
+ ((string-equal (file-notify--test-library) "kqueue")
+ '(changed created changed))
+ (t '(created changed))))
+ events)))
+
+ ;; Run the test.
+ (file-notify--test-with-events events
+ (dotimes (i n)
+ (read-event nil nil file-notify--test-read-event-timeout)
+ (if (zerop (mod i 2))
+ (write-region
+ "any text" nil file-notify--test-tmpfile1 t 'no-message)
+ (let ((temporary-file-directory file-notify--test-tmpfile))
+ (write-region
+ "any text" nil
+ (file-notify--test-make-temp-name) nil 'no-message)))))))
+
+ ;; If we delete the file, the directory monitor shall still be
+ ;; active. We receive the `deleted' event from both the
+ ;; directory and the file monitor. The `stopped' event is
+ ;; from the file monitor. It's undecided in which order the
+ ;; the directory and the file monitor are triggered.
+ (file-notify--test-with-events
+ '((deleted deleted stopped)
+ (deleted stopped deleted))
+ (delete-file file-notify--test-tmpfile1))
+ (should (file-notify-valid-p file-notify--test-desc1))
+ (should-not (file-notify-valid-p file-notify--test-desc2))
+
+ ;; Now we delete the directory.
+ (file-notify--test-with-events
+ (cond
+ ;; In kqueue, just one `deleted' event for the directory
+ ;; is received.
+ ((string-equal (file-notify--test-library) "kqueue")
+ '(deleted stopped))
+ (t (append
+ ;; The directory monitor raises a `deleted' event for
+ ;; every file contained in the directory, we must
+ ;; count them.
+ (make-list
+ (length
+ (directory-files
+ file-notify--test-tmpfile nil
+ directory-files-no-dot-files-regexp 'nosort))
+ 'deleted)
+ ;; The events of the directory itself.
+ '(deleted stopped))))
+ (delete-directory file-notify--test-tmpfile 'recursive))
+ (should-not (file-notify-valid-p file-notify--test-desc1))
+ (should-not (file-notify-valid-p file-notify--test-desc2)))
+
+ ;; Cleanup.
+ (file-notify--test-cleanup)))
+
+(file-notify--deftest-remote file-notify-test08-watched-file-in-watched-dir
+ "Check `file-notify-test08-watched-file-in-watched-dir' for remote files.")
+
(defun file-notify-test-all (&optional interactive)
"Run all tests for \\[file-notify]."
(interactive "p")