mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-12-23 10:34:07 +00:00
Merge branch 'master' into scratch/correct-warning-pos
This commit is contained in:
commit
14d64a8adc
1
.gitignore
vendored
1
.gitignore
vendored
@ -221,6 +221,7 @@ lisp/international/emoji-zwj.el
|
||||
lisp/international/emoji-labels.el
|
||||
lisp/international/eucjp-ms.el
|
||||
lisp/international/uni-*.el
|
||||
lisp/international/idna-mapping.el
|
||||
lisp/language/pinyin.el
|
||||
|
||||
# Documentation.
|
||||
|
@ -79,6 +79,8 @@ The GNU allocators don't work|\
|
||||
^git config |\
|
||||
^'\.git/|\
|
||||
^\^\(\(|\
|
||||
^ANCIENT=yes make|\
|
||||
^touch -t|\
|
||||
^'build-aux/git-hooks\
|
||||
" | \
|
||||
while read
|
||||
|
@ -15,20 +15,26 @@ Emacs uses the following files from the Unicode Character Database
|
||||
. BidiMirroring.txt
|
||||
. IVD_Sequences.txt
|
||||
. NormalizationTest.txt
|
||||
. PropertyValueAliases.txt
|
||||
. ScriptExtensions.txt
|
||||
. Scripts.txt
|
||||
. SpecialCasing.txt
|
||||
. confusables.txt
|
||||
. emoji-data.txt
|
||||
. emoji-zwj-sequences.txt
|
||||
. emoji-sequences.txt
|
||||
. BidiCharacterTest.txt
|
||||
|
||||
Emacs also uses the file emoji-test.txt which should be imported from
|
||||
the Unicode's Public/emoji/ directory.
|
||||
the Unicode's Public/emoji/ directory, and IdnaMappingTable.txt from
|
||||
the Public/idna/ directory.
|
||||
|
||||
First, the first 10 files and emoji-test.txt need to be copied into
|
||||
admin/unidata/, and the file https://www.unicode.org/copyright.html
|
||||
should be copied over copyright.html in admin/unidata (some of them
|
||||
might need trailing whitespace removed before they can be committed to
|
||||
the Emacs repository).
|
||||
First, the first 14 files, emoji-test.txt and IdnaMappingTable.txt
|
||||
need to be copied into admin/unidata/, and the file
|
||||
https://www.unicode.org/copyright.html should be copied over
|
||||
copyright.html in admin/unidata (some of them might need trailing
|
||||
whitespace removed before they can be committed to the Emacs
|
||||
repository).
|
||||
|
||||
Then Emacs should be rebuilt for them to take effect. Rebuilding
|
||||
Emacs updates several derived files elsewhere in the Emacs source
|
||||
|
8921
admin/unidata/IdnaMappingTable.txt
Normal file
8921
admin/unidata/IdnaMappingTable.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -44,7 +44,9 @@ unifiles = $(addprefix ${unidir}/,$(sort $(shell sed -n 's/^[ \t][ \t]*${lparen}
|
||||
.PHONY: all
|
||||
|
||||
all: ${top_srcdir}/src/macuvs.h ${unifiles} ${unidir}/charscript.el \
|
||||
${unidir}/charprop.el ${unidir}/emoji-zwj.el ${unidir}/emoji-labels.el
|
||||
${unidir}/charprop.el ${unidir}/emoji-zwj.el ${unidir}/emoji-labels.el \
|
||||
${unidir}/uni-scripts.el ${unidir}/uni-confusable.el \
|
||||
${unidir}/idna-mapping.el
|
||||
|
||||
## Specify .elc as an order-only prereq so as to not needlessly rebuild
|
||||
## target just because the .elc is missing.
|
||||
@ -82,6 +84,23 @@ ${unidir}/emoji-labels.el: ${unidir}/../international/emoji.el \
|
||||
${srcdir}/emoji-test.txt
|
||||
$(AM_V_GEN)${emacs} -l emoji.el -f emoji--generate-file $@
|
||||
|
||||
${unidir}/uni-scripts.el: ${srcdir}/unidata-gen.el \
|
||||
${srcdir}/Scripts.txt \
|
||||
${srcdir}/ScriptExtensions.txt \
|
||||
${srcdir}/PropertyValueAliases.txt
|
||||
$(AM_V_GEN)${emacs} -L ${srcdir} \
|
||||
-l unidata-gen.el -f unidata-gen-scripts $@
|
||||
|
||||
${unidir}/uni-confusable.el: ${srcdir}/unidata-gen.el \
|
||||
${srcdir}/confusables.txt
|
||||
$(AM_V_GEN)${emacs} -L ${srcdir} \
|
||||
-l unidata-gen.el -f unidata-gen-confusable $@
|
||||
|
||||
${unidir}/idna-mapping.el: ${srcdir}/unidata-gen.el \
|
||||
${srcdir}/IdnaMappingTable.txt
|
||||
$(AM_V_GEN)${emacs} -L ${srcdir} \
|
||||
-l unidata-gen.el -f unidata-gen-idna-mapping $@
|
||||
|
||||
.PHONY: charscript.el
|
||||
charscript.el: ${unidir}/charscript.el
|
||||
|
||||
|
1615
admin/unidata/PropertyValueAliases.txt
Normal file
1615
admin/unidata/PropertyValueAliases.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -48,3 +48,19 @@ https://www.unicode.org/Public/emoji/14.0/emoji-sequences.txt
|
||||
emoji-test.txt
|
||||
https://unicode.org/Public/emoji/14.0/emoji-test.txt
|
||||
2021-10-28
|
||||
|
||||
ScriptExtensions.txt
|
||||
https://www.unicode.org/Public/UCD/latest/ucd/ScriptExtensions.txt
|
||||
2022-01-17
|
||||
|
||||
Scripts.txt
|
||||
https://www.unicode.org/Public/UCD/latest/ucd/Scripts.txt
|
||||
2022-01-17
|
||||
|
||||
PropertyValueAliases.txt
|
||||
https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt
|
||||
2022-01-17
|
||||
|
||||
IdnaMappingTable.txt
|
||||
https://www.unicode.org/Public/idna/latest/IdnaMappingTable.txt
|
||||
2022-01-18
|
||||
|
628
admin/unidata/ScriptExtensions.txt
Normal file
628
admin/unidata/ScriptExtensions.txt
Normal file
@ -0,0 +1,628 @@
|
||||
# ScriptExtensions-14.0.0.txt
|
||||
# Date: 2021-06-04, 02:19:38 GMT
|
||||
# © 2021 Unicode®, Inc.
|
||||
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
|
||||
# For terms of use, see http://www.unicode.org/terms_of_use.html
|
||||
#
|
||||
# Unicode Character Database
|
||||
# For documentation, see http://www.unicode.org/reports/tr44/
|
||||
#
|
||||
# The Script_Extensions property indicates which characters are commonly used
|
||||
# with more than one script, but with a limited number of scripts.
|
||||
# For each code point, there is one or more property values. Each such value is a Script property value.
|
||||
# For more information, see:
|
||||
# UAX #24, Unicode Script Property: https://www.unicode.org/reports/tr24/
|
||||
# Especially the sections:
|
||||
# https://www.unicode.org/reports/tr24/#Assignment_Script_Values
|
||||
# https://www.unicode.org/reports/tr24/#Assignment_ScriptX_Values
|
||||
#
|
||||
# Each Script_Extensions value in this file consists of a set
|
||||
# of one or more abbreviated Script property values. The ordering of the
|
||||
# values in that set is not material, but for stability in presentation
|
||||
# it is given here as alphabetical.
|
||||
#
|
||||
# The Script_Extensions values are presented in sorted order in the file.
|
||||
# They are sorted first by the number of Script property values in their sets,
|
||||
# and then alphabetically by first differing Script property value.
|
||||
#
|
||||
# Following each distinct Script_Extensions value is the list of code
|
||||
# points associated with that value, listed in code point order.
|
||||
#
|
||||
# All code points not explicitly listed for Script_Extensions
|
||||
# have as their value the corresponding Script property value
|
||||
#
|
||||
# @missing: 0000..10FFFF; <script>
|
||||
|
||||
# ================================================
|
||||
|
||||
# Property: Script_Extensions
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng
|
||||
|
||||
1CF7 ; Beng # Mc VEDIC SIGN ATIKRAMA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva
|
||||
|
||||
1CD1 ; Deva # Mn VEDIC TONE SHARA
|
||||
1CD4 ; Deva # Mn VEDIC SIGN YAJURVEDIC MIDLINE SVARITA
|
||||
1CDB ; Deva # Mn VEDIC TONE TRIPLE SVARITA
|
||||
1CDE..1CDF ; Deva # Mn [2] VEDIC TONE TWO DOTS BELOW..VEDIC TONE THREE DOTS BELOW
|
||||
1CE2..1CE8 ; Deva # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
|
||||
1CEB..1CEC ; Deva # Lo [2] VEDIC SIGN ANUSVARA VAMAGOMUKHA..VEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAIL
|
||||
1CEE..1CF1 ; Deva # Lo [4] VEDIC SIGN HEXIFORM LONG ANUSVARA..VEDIC SIGN ANUSVARA UBHAYATO MUKHA
|
||||
|
||||
# Total code points: 18
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Dupl
|
||||
|
||||
1BCA0..1BCA3 ; Dupl # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
|
||||
|
||||
# Total code points: 4
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Grek
|
||||
|
||||
0342 ; Grek # Mn COMBINING GREEK PERISPOMENI
|
||||
0345 ; Grek # Mn COMBINING GREEK YPOGEGRAMMENI
|
||||
1DC0..1DC1 ; Grek # Mn [2] COMBINING DOTTED GRAVE ACCENT..COMBINING DOTTED ACUTE ACCENT
|
||||
|
||||
# Total code points: 4
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Hani
|
||||
|
||||
3006 ; Hani # Lo IDEOGRAPHIC CLOSING MARK
|
||||
303E..303F ; Hani # So [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE
|
||||
3190..3191 ; Hani # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
|
||||
3192..3195 ; Hani # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
|
||||
3196..319F ; Hani # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
|
||||
31C0..31E3 ; Hani # So [36] CJK STROKE T..CJK STROKE Q
|
||||
3220..3229 ; Hani # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN
|
||||
322A..3247 ; Hani # So [30] PARENTHESIZED IDEOGRAPH MOON..CIRCLED IDEOGRAPH KOTO
|
||||
3280..3289 ; Hani # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN
|
||||
328A..32B0 ; Hani # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT
|
||||
32C0..32CB ; Hani # So [12] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER
|
||||
32FF ; Hani # So SQUARE ERA NAME REIWA
|
||||
3358..3370 ; Hani # So [25] IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO..IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR
|
||||
337B..337F ; Hani # So [5] SQUARE ERA NAME HEISEI..SQUARE CORPORATION
|
||||
33E0..33FE ; Hani # So [31] IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE
|
||||
1D360..1D371 ; Hani # No [18] COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE
|
||||
1F250..1F251 ; Hani # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT
|
||||
|
||||
# Total code points: 238
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Latn
|
||||
|
||||
0363..036F ; Latn # Mn [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X
|
||||
|
||||
# Total code points: 13
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Nand
|
||||
|
||||
1CFA ; Nand # Lo VEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Syrc
|
||||
|
||||
1DFA ; Syrc # Mn COMBINING DOT BELOW LEFT
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Arab Copt
|
||||
|
||||
102E0 ; Arab Copt # Mn COPTIC EPACT THOUSANDS MARK
|
||||
102E1..102FB ; Arab Copt # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED
|
||||
|
||||
# Total code points: 28
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Arab Rohg
|
||||
|
||||
06D4 ; Arab Rohg # Po ARABIC FULL STOP
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Arab Nkoo
|
||||
|
||||
FD3E ; Arab Nkoo # Pe ORNATE LEFT PARENTHESIS
|
||||
FD3F ; Arab Nkoo # Ps ORNATE RIGHT PARENTHESIS
|
||||
|
||||
# Total code points: 2
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Arab Syrc
|
||||
|
||||
064B..0655 ; Arab Syrc # Mn [11] ARABIC FATHATAN..ARABIC HAMZA BELOW
|
||||
0670 ; Arab Syrc # Mn ARABIC LETTER SUPERSCRIPT ALEF
|
||||
|
||||
# Total code points: 12
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Arab Thaa
|
||||
|
||||
FDF2 ; Arab Thaa # Lo ARABIC LIGATURE ALLAH ISOLATED FORM
|
||||
FDFD ; Arab Thaa # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
|
||||
|
||||
# Total code points: 2
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng Deva
|
||||
|
||||
1CD5..1CD6 ; Beng Deva # Mn [2] VEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITA..VEDIC TONE YAJURVEDIC INDEPENDENT SVARITA
|
||||
1CD8 ; Beng Deva # Mn VEDIC TONE CANDRA BELOW
|
||||
1CE1 ; Beng Deva # Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA
|
||||
1CEA ; Beng Deva # Lo VEDIC SIGN ANUSVARA BAHIRGOMUKHA
|
||||
1CED ; Beng Deva # Mn VEDIC SIGN TIRYAK
|
||||
1CF5..1CF6 ; Beng Deva # Lo [2] VEDIC SIGN JIHVAMULIYA..VEDIC SIGN UPADHMANIYA
|
||||
A8F1 ; Beng Deva # Mn COMBINING DEVANAGARI SIGN AVAGRAHA
|
||||
|
||||
# Total code points: 9
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Bopo Hani
|
||||
|
||||
302A..302D ; Bopo Hani # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
|
||||
|
||||
# Total code points: 4
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Bugi Java
|
||||
|
||||
A9CF ; Bugi Java # Lm JAVANESE PANGRANGKEP
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Cprt Linb
|
||||
|
||||
10102 ; Cprt Linb # Po AEGEAN CHECK MARK
|
||||
10137..1013F ; Cprt Linb # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Cyrl Glag
|
||||
|
||||
0484 ; Cyrl Glag # Mn COMBINING CYRILLIC PALATALIZATION
|
||||
0487 ; Cyrl Glag # Mn COMBINING CYRILLIC POKRYTIE
|
||||
2E43 ; Cyrl Glag # Po DASH WITH LEFT UPTURN
|
||||
A66F ; Cyrl Glag # Mn COMBINING CYRILLIC VZMET
|
||||
|
||||
# Total code points: 4
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Cyrl Latn
|
||||
|
||||
0485..0486 ; Cyrl Latn # Mn [2] COMBINING CYRILLIC DASIA PNEUMATA..COMBINING CYRILLIC PSILI PNEUMATA
|
||||
|
||||
# Total code points: 2
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Cyrl Perm
|
||||
|
||||
0483 ; Cyrl Perm # Mn COMBINING CYRILLIC TITLO
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Cyrl Syrc
|
||||
|
||||
1DF8 ; Cyrl Syrc # Mn COMBINING DOT ABOVE LEFT
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Gran
|
||||
|
||||
1CD3 ; Deva Gran # Po VEDIC SIGN NIHSHVASA
|
||||
1CF3 ; Deva Gran # Lo VEDIC SIGN ROTATED ARDHAVISARGA
|
||||
1CF8..1CF9 ; Deva Gran # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
|
||||
|
||||
# Total code points: 4
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Nand
|
||||
|
||||
1CE9 ; Deva Nand # Lo VEDIC SIGN ANUSVARA ANTARGOMUKHA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Shrd
|
||||
|
||||
1CD7 ; Deva Shrd # Mn VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA
|
||||
1CD9 ; Deva Shrd # Mn VEDIC TONE YAJURVEDIC KATHAKA INDEPENDENT SVARITA SCHROEDER
|
||||
1CDC..1CDD ; Deva Shrd # Mn [2] VEDIC TONE KATHAKA ANUDATTA..VEDIC TONE DOT BELOW
|
||||
1CE0 ; Deva Shrd # Mn VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
|
||||
|
||||
# Total code points: 5
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Taml
|
||||
|
||||
A8F3 ; Deva Taml # Lo DEVANAGARI SIGN CANDRABINDU VIRAMA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Geor Latn
|
||||
|
||||
10FB ; Geor Latn # Po GEORGIAN PARAGRAPH SEPARATOR
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Gran Taml
|
||||
|
||||
0BE6..0BEF ; Gran Taml # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
|
||||
0BF0..0BF2 ; Gran Taml # No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND
|
||||
0BF3 ; Gran Taml # So TAMIL DAY SIGN
|
||||
11301 ; Gran Taml # Mn GRANTHA SIGN CANDRABINDU
|
||||
11303 ; Gran Taml # Mc GRANTHA SIGN VISARGA
|
||||
1133B..1133C ; Gran Taml # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
|
||||
11FD0..11FD1 ; Gran Taml # No [2] TAMIL FRACTION ONE QUARTER..TAMIL FRACTION ONE HALF-1
|
||||
11FD3 ; Gran Taml # No TAMIL FRACTION THREE QUARTERS
|
||||
|
||||
# Total code points: 21
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Gujr Khoj
|
||||
|
||||
0AE6..0AEF ; Gujr Khoj # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Guru Mult
|
||||
|
||||
0A66..0A6F ; Guru Mult # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Hani Latn
|
||||
|
||||
A700..A707 ; Hani Latn # Sk [8] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER CHINESE TONE YANG RU
|
||||
|
||||
# Total code points: 8
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Hira Kana
|
||||
|
||||
3031..3035 ; Hira Kana # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
|
||||
3099..309A ; Hira Kana # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
|
||||
309B..309C ; Hira Kana # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
|
||||
30A0 ; Hira Kana # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN
|
||||
30FC ; Hira Kana # Lm KATAKANA-HIRAGANA PROLONGED SOUND MARK
|
||||
FF70 ; Hira Kana # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
|
||||
FF9E..FF9F ; Hira Kana # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
|
||||
|
||||
# Total code points: 14
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Knda Nand
|
||||
|
||||
0CE6..0CEF ; Knda Nand # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Latn Mong
|
||||
|
||||
202F ; Latn Mong # Zs NARROW NO-BREAK SPACE
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Mani Ougr
|
||||
|
||||
10AF2 ; Mani Ougr # Po MANICHAEAN PUNCTUATION DOUBLE DOT WITHIN DOT
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Mong Phag
|
||||
|
||||
1802..1803 ; Mong Phag # Po [2] MONGOLIAN COMMA..MONGOLIAN FULL STOP
|
||||
1805 ; Mong Phag # Po MONGOLIAN FOUR DOTS
|
||||
|
||||
# Total code points: 3
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Arab Syrc Thaa
|
||||
|
||||
061C ; Arab Syrc Thaa # Cf ARABIC LETTER MARK
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Arab Thaa Yezi
|
||||
|
||||
0660..0669 ; Arab Thaa Yezi # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng Cakm Sylo
|
||||
|
||||
09E6..09EF ; Beng Cakm Sylo # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Cakm Mymr Tale
|
||||
|
||||
1040..1049 ; Cakm Mymr Tale # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Cpmn Cprt Linb
|
||||
|
||||
10100..10101 ; Cpmn Cprt Linb # Po [2] AEGEAN WORD SEPARATOR LINE..AEGEAN WORD SEPARATOR DOT
|
||||
|
||||
# Total code points: 2
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Cprt Lina Linb
|
||||
|
||||
10107..10133 ; Cprt Lina Linb # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND
|
||||
|
||||
# Total code points: 45
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Gran Knda
|
||||
|
||||
1CF4 ; Deva Gran Knda # Mn VEDIC TONE CANDRA ABOVE
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Gran Latn
|
||||
|
||||
20F0 ; Deva Gran Latn # Mn COMBINING ASTERISK ABOVE
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Hani Hira Kana
|
||||
|
||||
303C ; Hani Hira Kana # Lo MASU MARK
|
||||
303D ; Hani Hira Kana # Po PART ALTERNATION MARK
|
||||
|
||||
# Total code points: 2
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Kali Latn Mymr
|
||||
|
||||
A92E ; Kali Latn Mymr # Po KAYAH LI SIGN CWI
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng Deva Gran Knda
|
||||
|
||||
1CD0 ; Beng Deva Gran Knda # Mn VEDIC TONE KARSHANA
|
||||
1CD2 ; Beng Deva Gran Knda # Mn VEDIC TONE PRENKHA
|
||||
|
||||
# Total code points: 2
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Buhd Hano Tagb Tglg
|
||||
|
||||
1735..1736 ; Buhd Hano Tagb Tglg # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
|
||||
|
||||
# Total code points: 2
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Dogr Kthi Mahj
|
||||
|
||||
0966..096F ; Deva Dogr Kthi Mahj # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Bopo Hang Hani Hira Kana
|
||||
|
||||
3003 ; Bopo Hang Hani Hira Kana # Po DITTO MARK
|
||||
3013 ; Bopo Hang Hani Hira Kana # So GETA MARK
|
||||
301C ; Bopo Hang Hani Hira Kana # Pd WAVE DASH
|
||||
301D ; Bopo Hang Hani Hira Kana # Ps REVERSED DOUBLE PRIME QUOTATION MARK
|
||||
301E..301F ; Bopo Hang Hani Hira Kana # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
|
||||
3030 ; Bopo Hang Hani Hira Kana # Pd WAVY DASH
|
||||
3037 ; Bopo Hang Hani Hira Kana # So IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
|
||||
FE45..FE46 ; Bopo Hang Hani Hira Kana # Po [2] SESAME DOT..WHITE SESAME DOT
|
||||
|
||||
# Total code points: 10
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Arab Nkoo Rohg Syrc Thaa Yezi
|
||||
|
||||
060C ; Arab Nkoo Rohg Syrc Thaa Yezi # Po ARABIC COMMA
|
||||
061B ; Arab Nkoo Rohg Syrc Thaa Yezi # Po ARABIC SEMICOLON
|
||||
|
||||
# Total code points: 2
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Bopo Hang Hani Hira Kana Yiii
|
||||
|
||||
3001..3002 ; Bopo Hang Hani Hira Kana Yiii # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP
|
||||
3008 ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT ANGLE BRACKET
|
||||
3009 ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT ANGLE BRACKET
|
||||
300A ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT DOUBLE ANGLE BRACKET
|
||||
300B ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT DOUBLE ANGLE BRACKET
|
||||
300C ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT CORNER BRACKET
|
||||
300D ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT CORNER BRACKET
|
||||
300E ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT WHITE CORNER BRACKET
|
||||
300F ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT WHITE CORNER BRACKET
|
||||
3010 ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT BLACK LENTICULAR BRACKET
|
||||
3011 ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT BLACK LENTICULAR BRACKET
|
||||
3014 ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT TORTOISE SHELL BRACKET
|
||||
3015 ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT TORTOISE SHELL BRACKET
|
||||
3016 ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT WHITE LENTICULAR BRACKET
|
||||
3017 ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT WHITE LENTICULAR BRACKET
|
||||
3018 ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT WHITE TORTOISE SHELL BRACKET
|
||||
3019 ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT WHITE TORTOISE SHELL BRACKET
|
||||
301A ; Bopo Hang Hani Hira Kana Yiii # Ps LEFT WHITE SQUARE BRACKET
|
||||
301B ; Bopo Hang Hani Hira Kana Yiii # Pe RIGHT WHITE SQUARE BRACKET
|
||||
30FB ; Bopo Hang Hani Hira Kana Yiii # Po KATAKANA MIDDLE DOT
|
||||
FF61 ; Bopo Hang Hani Hira Kana Yiii # Po HALFWIDTH IDEOGRAPHIC FULL STOP
|
||||
FF62 ; Bopo Hang Hani Hira Kana Yiii # Ps HALFWIDTH LEFT CORNER BRACKET
|
||||
FF63 ; Bopo Hang Hani Hira Kana Yiii # Pe HALFWIDTH RIGHT CORNER BRACKET
|
||||
FF64..FF65 ; Bopo Hang Hani Hira Kana Yiii # Po [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT
|
||||
|
||||
# Total code points: 26
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Knda Mlym Orya Taml Telu
|
||||
|
||||
1CDA ; Deva Knda Mlym Orya Taml Telu # Mn VEDIC TONE DOUBLE SVARITA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Adlm Arab Nkoo Rohg Syrc Thaa Yezi
|
||||
|
||||
061F ; Adlm Arab Nkoo Rohg Syrc Thaa Yezi # Po ARABIC QUESTION MARK
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng Deva Gran Knda Nand Orya Telu Tirh
|
||||
|
||||
1CF2 ; Beng Deva Gran Knda Nand Orya Telu Tirh # Lo VEDIC SIGN ARDHAVISARGA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Adlm Arab Mand Mani Ougr Phlp Rohg Sogd Syrc
|
||||
|
||||
0640 ; Adlm Arab Mand Mani Ougr Phlp Rohg Sogd Syrc # Lm ARABIC TATWEEL
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Dogr Gujr Guru Khoj Kthi Mahj Modi Sind Takr Tirh
|
||||
|
||||
A836..A837 ; Deva Dogr Gujr Guru Khoj Kthi Mahj Modi Sind Takr Tirh # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK
|
||||
A838 ; Deva Dogr Gujr Guru Khoj Kthi Mahj Modi Sind Takr Tirh # Sc NORTH INDIC RUPEE MARK
|
||||
A839 ; Deva Dogr Gujr Guru Khoj Kthi Mahj Modi Sind Takr Tirh # So NORTH INDIC QUANTITY MARK
|
||||
|
||||
# Total code points: 4
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng Deva Gran Gujr Guru Knda Latn Mlym Orya Taml Telu Tirh
|
||||
|
||||
0952 ; Beng Deva Gran Gujr Guru Knda Latn Mlym Orya Taml Telu Tirh # Mn DEVANAGARI STRESS SIGN ANUDATTA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng Deva Gran Gujr Guru Knda Latn Mlym Orya Shrd Taml Telu Tirh
|
||||
|
||||
0951 ; Beng Deva Gran Gujr Guru Knda Latn Mlym Orya Shrd Taml Telu Tirh # Mn DEVANAGARI STRESS SIGN UDATTA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Dogr Gujr Guru Khoj Knda Kthi Mahj Modi Nand Sind Takr Tirh
|
||||
|
||||
A833..A835 ; Deva Dogr Gujr Guru Khoj Knda Kthi Mahj Modi Nand Sind Takr Tirh # No [3] NORTH INDIC FRACTION ONE SIXTEENTH..NORTH INDIC FRACTION THREE SIXTEENTHS
|
||||
|
||||
# Total code points: 3
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Deva Dogr Gujr Guru Khoj Knda Kthi Mahj Mlym Modi Nand Sind Takr Tirh
|
||||
|
||||
A830..A832 ; Deva Dogr Gujr Guru Khoj Knda Kthi Mahj Mlym Modi Nand Sind Takr Tirh # No [3] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC FRACTION THREE QUARTERS
|
||||
|
||||
# Total code points: 3
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng Deva Dogr Gong Gonm Gran Gujr Guru Knda Mahj Mlym Nand Orya Sind Sinh Sylo Takr Taml Telu Tirh
|
||||
|
||||
0964 ; Beng Deva Dogr Gong Gonm Gran Gujr Guru Knda Mahj Mlym Nand Orya Sind Sinh Sylo Takr Taml Telu Tirh # Po DEVANAGARI DANDA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# ================================================
|
||||
|
||||
# Script_Extensions=Beng Deva Dogr Gong Gonm Gran Gujr Guru Knda Limb Mahj Mlym Nand Orya Sind Sinh Sylo Takr Taml Telu Tirh
|
||||
|
||||
0965 ; Beng Deva Dogr Gong Gonm Gran Gujr Guru Knda Limb Mahj Mlym Nand Orya Sind Sinh Sylo Takr Taml Telu Tirh # Po DEVANAGARI DOUBLE DANDA
|
||||
|
||||
# Total code points: 1
|
||||
|
||||
# EOF
|
2991
admin/unidata/Scripts.txt
Normal file
2991
admin/unidata/Scripts.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -98,7 +98,7 @@ function name2alias(name , w, w2) {
|
||||
else if (name ~ /arabic/) return "arabic"
|
||||
else if (name ~ /^greek/) return "greek"
|
||||
else if (name ~ /^coptic/) return "coptic"
|
||||
else if (name ~ /cuneiform number/) return "cuneiform-numbers-and-punctuation"
|
||||
else if (name ~ /cuneiform number/) return "cuneiform"
|
||||
else if (name ~ /cuneiform/) return "cuneiform"
|
||||
else if (name ~ /mathematical alphanumeric symbol/) return "mathematical"
|
||||
else if (name ~ /punctuation|mathematical|arrows|currency|superscript|small form variants|geometric|dingbats|enclosed|alchemical|pictograph|emoticon|transport/) return "symbol"
|
||||
@ -113,9 +113,11 @@ function name2alias(name , w, w2) {
|
||||
else if (name ~/^(specials|tags)$/) return 0
|
||||
else if (name ~ /linear b/) return "linear-b"
|
||||
else if (name ~ /aramaic/) return "aramaic"
|
||||
else if (name ~ /rumi num/) return "rumi-number"
|
||||
else if (name ~ /rumi num/) return "arabic"
|
||||
else if (name ~ /duployan|shorthand/) return "duployan-shorthand"
|
||||
else if (name ~ /sutton signwriting/) return "sutton-sign-writing"
|
||||
else if (name ~ /sinhala archaic number/) return "sinhala"
|
||||
else if (name ~ /tangut components/) return "tangut"
|
||||
|
||||
sub(/^small /, "", name)
|
||||
sub(/ (extended|extensions*|supplement).*/, "", name)
|
||||
|
9637
admin/unidata/confusables.txt
Normal file
9637
admin/unidata/confusables.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -1449,20 +1449,24 @@ Property value is a symbol `o' (Open), `c' (Close), or `n' (None)."
|
||||
(format ";;; %s ends here\n" basename)))))
|
||||
(or noninteractive (message "Generating %s...done" file)))
|
||||
|
||||
(defun unidata-gen-charprop (&optional charprop-file)
|
||||
(defun unidata-gen-charprop (&optional charprop-file text)
|
||||
(or charprop-file (setq charprop-file (pop command-line-args-left)))
|
||||
(with-temp-file charprop-file
|
||||
(insert ";; Automatically generated by unidata-gen.el."
|
||||
" -*- lexical-binding: t -*-\n"
|
||||
";; See the admin/unidata/ directory in the Emacs sources.\n")
|
||||
(dolist (elt unidata-file-alist)
|
||||
(dolist (proplist (cdr elt))
|
||||
(insert (format "(define-char-code-property '%S %S\n %S)\n"
|
||||
(unidata-prop-prop proplist) (car elt)
|
||||
(unidata-prop-docstring proplist)))))
|
||||
(if text
|
||||
(insert text)
|
||||
(dolist (elt unidata-file-alist)
|
||||
(dolist (proplist (cdr elt))
|
||||
(insert (format "(define-char-code-property '%S %S\n %S)\n"
|
||||
(unidata-prop-prop proplist) (car elt)
|
||||
(unidata-prop-docstring proplist))))))
|
||||
(or noninteractive (message "Writing %s..." charprop-file))
|
||||
(insert "\n"
|
||||
"(provide 'charprop)\n"
|
||||
(format "(provide '%s)\n"
|
||||
(file-name-sans-extension
|
||||
(file-name-nondirectory charprop-file)))
|
||||
"\n"
|
||||
";; Local Variables:\n"
|
||||
";; coding: utf-8\n"
|
||||
@ -1473,6 +1477,171 @@ Property value is a symbol `o' (Open), `c' (Close), or `n' (None)."
|
||||
(format ";;; %s ends here\n"
|
||||
(file-name-nondirectory charprop-file)))))
|
||||
|
||||
(defun unidata-gen-scripts (&optional file)
|
||||
;; Running from Makefile.
|
||||
(unless file
|
||||
(setq file (pop command-line-args-left)))
|
||||
(let ((aliases (unidata-gen--read-script-aliases))
|
||||
(table (make-char-table nil))
|
||||
(segmented (make-hash-table :test #'equal)))
|
||||
;; First parse the scripts.
|
||||
(with-temp-buffer
|
||||
(unidata-gen--insert-file "Scripts.txt")
|
||||
(while (not (eobp))
|
||||
;; 1700..1711 ; Tagalog # Lo [18] TAGALOG LETTER A..TAGALOG
|
||||
(when (looking-at "\\([0-9A-F]+\\)\\(?:\\.\\.\\([0-9A-F]+\\)\\)? +; +\\([^ ]+\\) +#")
|
||||
(let ((start (string-to-number (match-string 1) 16))
|
||||
(end (and (match-string 2)
|
||||
(string-to-number (match-string 2) 16)))
|
||||
(scripts (list (intern (string-replace
|
||||
"_" "-"
|
||||
(downcase (match-string 3)))))))
|
||||
(set-char-table-range
|
||||
table (if end (cons start end) start) scripts)))
|
||||
(forward-line 1)))
|
||||
|
||||
;; Then parse the file that lists "other scripts" that characters
|
||||
;; may appear in, and add those.
|
||||
(with-temp-buffer
|
||||
(unidata-gen--insert-file "ScriptExtensions.txt")
|
||||
(while (not (eobp))
|
||||
;; 102E0 ; Arab Copt # Mn COPTIC EPACT THOUSANDS MARK
|
||||
(when (looking-at "\\([0-9A-F]+\\)\\(?:\\.\\.\\([0-9A-F]+\\)\\)? +; +\\([^#]+\\)")
|
||||
(let ((start (string-to-number (match-string 1) 16))
|
||||
(end (and (match-string 2)
|
||||
(string-to-number (match-string 2) 16)))
|
||||
(scripts
|
||||
(mapcar
|
||||
(lambda (alias)
|
||||
(intern (string-replace
|
||||
"_" "-" (downcase
|
||||
(gethash alias aliases)))))
|
||||
(split-string (string-trim (match-string 3))))))
|
||||
(dolist (script scripts)
|
||||
(dotimes (i (- (1+ (or end start)) start))
|
||||
(set-char-table-range
|
||||
table (+ i start)
|
||||
(append (elt table (+ i start)) (list script)))))))
|
||||
(forward-line 1)))
|
||||
|
||||
;; Then go through the data and collect into buckets based on
|
||||
;; identical script lists.
|
||||
(map-char-table
|
||||
(lambda (key value)
|
||||
;; `map-char-table' is reused, so copy it.
|
||||
(push (if (consp key)
|
||||
(cons (car key) (cdr key))
|
||||
key)
|
||||
;; Keep the first element first, but sort the rest.
|
||||
(gethash (cons (car value)
|
||||
(sort (remq (car value) value) #'string<))
|
||||
segmented)))
|
||||
table)
|
||||
|
||||
;; Then go through the data and collect into buckets based on
|
||||
(let ((scripts nil))
|
||||
(maphash
|
||||
(lambda (segment chars)
|
||||
(push (cons segment chars) scripts))
|
||||
segmented)
|
||||
(setq scripts (sort scripts (lambda (s1 s2)
|
||||
(string< (caar s1) (caar s2)))))
|
||||
(with-temp-buffer
|
||||
(insert "(textsec--create-script-table '(\n")
|
||||
(dolist (script scripts)
|
||||
(insert "(" (prin1-to-string (car script)) "\n")
|
||||
(insert " " (prin1-to-string (cdr script)))
|
||||
(insert ")\n"))
|
||||
(insert "))\n")
|
||||
;; Write the file.
|
||||
(unidata-gen-charprop file (buffer-string))))))
|
||||
|
||||
(defun unidata-gen--read-script-aliases ()
|
||||
(let ((aliases (make-hash-table :test #'equal)))
|
||||
(with-temp-buffer
|
||||
(unidata-gen--insert-file "PropertyValueAliases.txt")
|
||||
(unless (re-search-forward "^# Script " nil t)
|
||||
(error "Can't find the Script section"))
|
||||
(forward-line 2)
|
||||
(while (looking-at "sc *;")
|
||||
(let ((elem (split-string (buffer-substring (point) (line-end-position))
|
||||
";" nil "[ \t]+")))
|
||||
(setf (gethash (nth 1 elem) aliases)
|
||||
(nth 2 elem)))
|
||||
(forward-line 1))
|
||||
aliases)))
|
||||
|
||||
(defun unidata-gen--insert-file (name)
|
||||
(insert-file-contents
|
||||
(expand-file-name (concat "../admin/unidata/" name)
|
||||
data-directory)))
|
||||
|
||||
(defun unidata-gen-confusable (&optional file)
|
||||
;; Running from Makefile.
|
||||
(unless file
|
||||
(setq file (pop command-line-args-left)))
|
||||
(let ((regexp
|
||||
(concat "^\\([[:xdigit:]]+\\)"
|
||||
"[ \t]*;[ \t]*"
|
||||
"\\([[:space:][:xdigit:]]+\\)"
|
||||
"[ \t]*;"))
|
||||
(map (make-hash-table)))
|
||||
(with-temp-buffer
|
||||
(unidata-gen--insert-file "confusables.txt")
|
||||
(while (re-search-forward regexp nil t)
|
||||
(let ((from (match-string 1))
|
||||
(to (string-trim (match-string 2))))
|
||||
(setf (gethash (string-to-number from 16) map)
|
||||
(apply #'string (mapcar (lambda (string)
|
||||
(string-to-number string 16))
|
||||
(split-string to)))))))
|
||||
(with-temp-buffer
|
||||
(insert "(defconst uni-confusable-table\n")
|
||||
(let ((print-length nil))
|
||||
(prin1 map (current-buffer)))
|
||||
(insert ")")
|
||||
(unidata-gen-charprop file (buffer-string)))))
|
||||
|
||||
(defun unidata-gen-idna-mapping (&optional file)
|
||||
;; Running from Makefile.
|
||||
(unless file
|
||||
(setq file (pop command-line-args-left)))
|
||||
(let ((map (make-char-table nil)))
|
||||
(with-temp-buffer
|
||||
(unidata-gen--insert-file "IdnaMappingTable.txt")
|
||||
(while (re-search-forward "^\\([0-9A-F]+\\)\\(?:\\.\\.\\([0-9A-F]+\\)\\)? +; +\\([^ ]+\\) +\\(?:; +\\([ 0-9A-F]+\\)\\)?"
|
||||
nil t)
|
||||
(let ((start (match-string 1))
|
||||
(end (match-string 2))
|
||||
(status (match-string 3))
|
||||
(mapped (match-string 4)))
|
||||
;; Make reading the file slightly faster by using `t'
|
||||
;; instead of `disallowed' all over the place.
|
||||
(when (string-match-p "\\`disallowed" status)
|
||||
(setq status "t"))
|
||||
(unless (or (equal status "valid")
|
||||
(equal status "deviation"))
|
||||
(set-char-table-range
|
||||
map
|
||||
(if end
|
||||
(cons (string-to-number start 16)
|
||||
(string-to-number end 16))
|
||||
(string-to-number start 16))
|
||||
(cond
|
||||
((equal status "mapped")
|
||||
(apply #'string
|
||||
(mapcar (lambda (char)
|
||||
(string-to-number char 16))
|
||||
(split-string (string-trim mapped)))))
|
||||
(t
|
||||
(intern status))))))))
|
||||
(with-temp-buffer
|
||||
(insert "(defconst idna-mapping-table\n")
|
||||
(let ((print-length nil))
|
||||
(prin1 map (current-buffer)))
|
||||
(insert ")")
|
||||
(unidata-gen-charprop file (buffer-string)))))
|
||||
|
||||
|
||||
|
||||
;;; unidata-gen.el ends here
|
||||
|
133
configure.ac
133
configure.ac
@ -2913,40 +2913,6 @@ if test "${HAVE_GTK}" = "yes"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
dnl Enable xwidgets if GTK3 and WebKitGTK+ are available.
|
||||
dnl Enable xwidgets if macOS Cocoa and WebKit framework are available.
|
||||
HAVE_XWIDGETS=no
|
||||
XWIDGETS_OBJ=
|
||||
if test "$with_xwidgets" != "no"; then
|
||||
if test "$USE_GTK_TOOLKIT" = "GTK3" && test "$window_system" != "none"; then
|
||||
WEBKIT_REQUIRED=2.12
|
||||
WEBKIT_MODULES="webkit2gtk-4.0 >= $WEBKIT_REQUIRED"
|
||||
EMACS_CHECK_MODULES([WEBKIT], [$WEBKIT_MODULES])
|
||||
HAVE_XWIDGETS=$HAVE_WEBKIT
|
||||
XWIDGETS_OBJ="xwidget.o"
|
||||
elif test "${NS_IMPL_COCOA}" = "yes"; then
|
||||
dnl FIXME: Check framework WebKit2
|
||||
dnl WEBKIT_REQUIRED=M.m.p
|
||||
WEBKIT_LIBS="-Wl,-framework -Wl,WebKit"
|
||||
WEBKIT_CFLAGS="-I/System/Library/Frameworks/WebKit.framework/Headers"
|
||||
HAVE_WEBKIT="yes"
|
||||
HAVE_XWIDGETS=$HAVE_WEBKIT
|
||||
XWIDGETS_OBJ="xwidget.o"
|
||||
NS_OBJC_OBJ="$NS_OBJC_OBJ nsxwidget.o"
|
||||
dnl Update NS_OBJC_OBJ with added nsxwidget.o
|
||||
AC_SUBST(NS_OBJC_OBJ)
|
||||
else
|
||||
AC_MSG_ERROR([xwidgets requested, it requires GTK3 as X window toolkit or macOS Cocoa as window system.])
|
||||
fi
|
||||
|
||||
test $HAVE_XWIDGETS = yes ||
|
||||
AC_MSG_ERROR([xwidgets requested but WebKitGTK+ or WebKit framework not found.])
|
||||
|
||||
AC_DEFINE([HAVE_XWIDGETS], 1, [Define to 1 if you have xwidgets support.])
|
||||
fi
|
||||
AC_SUBST(XWIDGETS_OBJ)
|
||||
|
||||
CFLAGS=$OLD_CFLAGS
|
||||
LIBS=$OLD_LIBS
|
||||
|
||||
@ -3409,41 +3375,6 @@ if test "${with_xim}" != "no"; then
|
||||
[Define to 1 to default runtime use of XIM to on.])
|
||||
fi
|
||||
|
||||
|
||||
if test "${HAVE_XIM}" != "no"; then
|
||||
late_CFLAGS=$CFLAGS
|
||||
if test "$GCC" = yes; then
|
||||
CFLAGS="$CFLAGS --pedantic-errors"
|
||||
fi
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xresource.h>]],
|
||||
[[Display *display;
|
||||
XrmDatabase db;
|
||||
char *res_name;
|
||||
char *res_class;
|
||||
XIDProc *callback;
|
||||
XPointer *client_data;
|
||||
#ifndef __GNUC__
|
||||
/* If we're not using GCC, it's probably not XFree86, and this is
|
||||
probably right, but we can't use something like --pedantic-errors. */
|
||||
extern Bool XRegisterIMInstantiateCallback(Display*, XrmDatabase, char*,
|
||||
char*, XIMProc, XPointer*);
|
||||
#endif
|
||||
(void)XRegisterIMInstantiateCallback(display, db, res_name, res_class, callback,
|
||||
client_data);]])],
|
||||
[emacs_cv_arg6_star=yes])
|
||||
AH_TEMPLATE(XRegisterIMInstantiateCallback_arg6,
|
||||
[Define to the type of the 6th arg of XRegisterIMInstantiateCallback,
|
||||
either XPointer or XPointer*.])dnl
|
||||
if test "$emacs_cv_arg6_star" = yes; then
|
||||
AC_DEFINE(XRegisterIMInstantiateCallback_arg6, [XPointer*])
|
||||
else
|
||||
AC_DEFINE(XRegisterIMInstantiateCallback_arg6, [XPointer])
|
||||
fi
|
||||
CFLAGS=$late_CFLAGS
|
||||
fi
|
||||
|
||||
# Check for XRender
|
||||
HAVE_XRENDER=no
|
||||
if test "${HAVE_X11}" = "yes"; then
|
||||
@ -3468,6 +3399,13 @@ if test "${HAVE_X11}" = "yes"; then
|
||||
CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
|
||||
EMACS_CHECK_MODULES(CAIRO, $CAIRO_MODULE)
|
||||
if test $HAVE_CAIRO = yes; then
|
||||
CAIRO_XCB_MODULE="cairo-xcb >= $CAIRO_REQUIRED"
|
||||
EMACS_CHECK_MODULES(CAIRO_XCB, $CAIRO_XCB_MODULE)
|
||||
if test $HAVE_CAIRO_XCB = yes; then
|
||||
CAIRO_CFLAGS="$CAIRO_CFLAGS $CAIRO_XCB_CFLAGS"
|
||||
CAIRO_LIBS="$CAIRO_LIBS $CAIRO_XCB_LIBS"
|
||||
AC_DEFINE(USE_CAIRO_XCB, 1, [Define to 1 if cairo XCB surfaces are available.])
|
||||
fi
|
||||
AC_DEFINE(USE_CAIRO, 1, [Define to 1 if using cairo.])
|
||||
CFLAGS="$CFLAGS $CAIRO_CFLAGS"
|
||||
LIBS="$LIBS $CAIRO_LIBS"
|
||||
@ -3479,6 +3417,51 @@ if test "${HAVE_X11}" = "yes"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Enable xwidgets if GTK3 and WebKitGTK+ are available.
|
||||
dnl Enable xwidgets if macOS Cocoa and WebKit framework are available.
|
||||
HAVE_XWIDGETS=no
|
||||
XWIDGETS_OBJ=
|
||||
if test "$with_xwidgets" != "no"; then
|
||||
if test "$USE_GTK_TOOLKIT" = "GTK3" && test "$window_system" != "none"; then
|
||||
WEBKIT_REQUIRED=2.12
|
||||
WEBKIT_MODULES="webkit2gtk-4.0 >= $WEBKIT_REQUIRED"
|
||||
EMACS_CHECK_MODULES([WEBKIT], [$WEBKIT_MODULES])
|
||||
HAVE_XWIDGETS=$HAVE_WEBKIT
|
||||
XWIDGETS_OBJ="xwidget.o"
|
||||
if test "$HAVE_X_WINDOWS" = "yes" && test "${with_cairo}" = "no"; then
|
||||
CAIRO_XLIB_MODULES="cairo >= 1.8.0 cairo-xlib >= 1.8.0"
|
||||
EMACS_CHECK_MODULES(CAIRO_XLIB, $CAIRO_XLIB_MODULES)
|
||||
if test $HAVE_CAIRO_XLIB = "yes"; then
|
||||
CAIRO_CFLAGS="$CAIRO_XLIB_CFLAGS"
|
||||
CAIRO_LIBS="$CAIRO_XLIB_LIBS"
|
||||
AC_SUBST(CAIRO_CFLAGS)
|
||||
AC_SUBST(CAIRO_LIBS)
|
||||
else
|
||||
AC_MSG_ERROR([xwidgets requested, but a suitable cairo installation wasn't found])
|
||||
fi
|
||||
fi
|
||||
elif test "${NS_IMPL_COCOA}" = "yes"; then
|
||||
dnl FIXME: Check framework WebKit2
|
||||
dnl WEBKIT_REQUIRED=M.m.p
|
||||
WEBKIT_LIBS="-Wl,-framework -Wl,WebKit"
|
||||
WEBKIT_CFLAGS="-I/System/Library/Frameworks/WebKit.framework/Headers"
|
||||
HAVE_WEBKIT="yes"
|
||||
HAVE_XWIDGETS=$HAVE_WEBKIT
|
||||
XWIDGETS_OBJ="xwidget.o"
|
||||
NS_OBJC_OBJ="$NS_OBJC_OBJ nsxwidget.o"
|
||||
dnl Update NS_OBJC_OBJ with added nsxwidget.o
|
||||
AC_SUBST(NS_OBJC_OBJ)
|
||||
else
|
||||
AC_MSG_ERROR([xwidgets requested, it requires GTK3 as X window toolkit or macOS Cocoa as window system.])
|
||||
fi
|
||||
|
||||
test $HAVE_XWIDGETS = yes ||
|
||||
AC_MSG_ERROR([xwidgets requested but WebKitGTK+ or WebKit framework not found.])
|
||||
|
||||
AC_DEFINE([HAVE_XWIDGETS], 1, [Define to 1 if you have xwidgets support.])
|
||||
fi
|
||||
AC_SUBST(XWIDGETS_OBJ)
|
||||
|
||||
if test "$window_system" = "pgtk"; then
|
||||
CAIRO_REQUIRED=1.12.0
|
||||
CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
|
||||
@ -3750,20 +3733,24 @@ AC_SUBST(LIBOTF_LIBS)
|
||||
AC_SUBST(M17N_FLT_CFLAGS)
|
||||
AC_SUBST(M17N_FLT_LIBS)
|
||||
|
||||
XCB_LIBS=
|
||||
if test "${HAVE_X11}" = "yes"; then
|
||||
AC_CHECK_HEADER(X11/Xlib-xcb.h,
|
||||
AC_CHECK_LIB(xcb, xcb_translate_coordinates, HAVE_XCB=yes))
|
||||
if test "${HAVE_XCB}" = "yes"; then
|
||||
AC_CHECK_LIB(X11-xcb, XGetXCBConnection, HAVE_X11_XCB=yes)
|
||||
if test "${HAVE_X11_XCB}" = "yes"; then
|
||||
AC_DEFINE(USE_XCB, 1,
|
||||
AC_CHECK_LIB(xcb-util, xcb_aux_sync, HAVE_XCB_UTIL=yes)
|
||||
if test "${HAVE_XCB_UTIL}" = "yes"; then
|
||||
AC_DEFINE(USE_XCB, 1,
|
||||
[Define to 1 if you have the XCB library and X11-XCB library for mixed
|
||||
X11/XCB programming.])
|
||||
XCB_LIBS="-lX11-xcb -lxcb"
|
||||
AC_SUBST(XCB_LIBS)
|
||||
X11/XCB programming.])
|
||||
XCB_LIBS="-lX11-xcb -lxcb -lxcb-util"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(XCB_LIBS)
|
||||
|
||||
### Use -lXpm if available, unless '--with-xpm=no'.
|
||||
### mingw32 doesn't use -lXpm, since it loads the library dynamically.
|
||||
|
@ -629,7 +629,6 @@ buffer, but killing an indirect buffer has no effect on its base buffer.
|
||||
One way to use indirect buffers is to display multiple views of an
|
||||
outline. @xref{Outline Views}.
|
||||
|
||||
@vindex clone-indirect-buffer-hook
|
||||
A quick and handy way to make an indirect buffer is with the command
|
||||
@kbd{M-x clone-indirect-buffer}. It creates and selects an indirect
|
||||
buffer whose base buffer is the current buffer. With a numeric
|
||||
@ -637,14 +636,19 @@ argument, it prompts for the name of the indirect buffer; otherwise it
|
||||
uses the name of the current buffer, with a @samp{<@var{n}>} suffix
|
||||
added. @kbd{C-x 4 c} (@code{clone-indirect-buffer-other-window})
|
||||
works like @kbd{M-x clone-indirect-buffer}, but it selects the new
|
||||
buffer in another window. These functions run the hook
|
||||
@code{clone-indirect-buffer-hook} after creating the indirect buffer.
|
||||
buffer in another window.
|
||||
|
||||
The more general way to make an indirect buffer is with the command
|
||||
@kbd{M-x make-indirect-buffer}. It creates an indirect buffer
|
||||
named @var{indirect-name} from a buffer @var{base-buffer}, prompting for
|
||||
both using the minibuffer.
|
||||
|
||||
@vindex clone-indirect-buffer-hook
|
||||
The functions that create indirect buffers run the hook
|
||||
@code{clone-indirect-buffer-hook} after creating the indirect buffer.
|
||||
When this hook runs, the newly created indirect buffer is the current
|
||||
buffer.
|
||||
|
||||
@node Buffer Convenience
|
||||
@section Convenience Features and Customization of Buffer Handling
|
||||
|
||||
|
@ -1633,13 +1633,14 @@ Parameters,,, elisp, The Emacs Lisp Reference Manual}, and also
|
||||
For additional customization options for displaying tooltips, use
|
||||
@kbd{M-x customize-group @key{RET} tooltip @key{RET}}.
|
||||
|
||||
@vindex x-gtk-use-system-tooltips
|
||||
If Emacs is built with GTK+ support, it displays tooltips via GTK+,
|
||||
using the default appearance of GTK+ tooltips. To disable this,
|
||||
change the variable @code{x-gtk-use-system-tooltips} to @code{nil}.
|
||||
If you do this, or if Emacs is built without GTK+ support, most
|
||||
attributes of the tooltip text are specified by the @code{tooltip}
|
||||
face, and by X resources (@pxref{X Resources}).
|
||||
@vindex use-system-tooltips
|
||||
If Emacs is built with the GTK+ toolkit or Haiku windowing support,
|
||||
it displays tooltips via the toolkit, using the default appearance of
|
||||
the toolkit's tooltips. To disable this, change the variable
|
||||
@code{use-system-tooltips} to @code{nil}. If you do this, or if Emacs
|
||||
is built without GTK+ or Haiku windowing support, most attributes of
|
||||
the tooltip text are specified by the @code{tooltip} face, and by X
|
||||
resources (@pxref{X Resources}).
|
||||
|
||||
@dfn{GUD tooltips} are special tooltips that show the values of
|
||||
variables when debugging a program with GUD@. @xref{Debugger
|
||||
|
@ -85,16 +85,12 @@ instead.
|
||||
|
||||
@cindex tooltips (haiku)
|
||||
@cindex haiku tooltips
|
||||
@vindex haiku-use-system-tooltips
|
||||
On Haiku, Emacs defaults to using the system tooltip mechanism.
|
||||
This usually leads to more responsive tooltips, but the tooltips will
|
||||
not be able to display text properties or faces. If you need those
|
||||
features, customize the variable @code{haiku-use-system-tooltips} to
|
||||
the nil value, and Emacs will use its own implementation of tooltips.
|
||||
|
||||
Both system tooltips and Emacs's own tooltips cannot display above
|
||||
the menu bar, so help text in the menu bar will display in the echo
|
||||
area instead.
|
||||
features, customize the variable @code{use-system-tooltips} to the
|
||||
@code{nil} value, and Emacs will use its own implementation of
|
||||
tooltips.
|
||||
|
||||
@cindex X resources on Haiku
|
||||
Unlike the X window system, Haiku does not have a system-wide
|
||||
|
@ -463,14 +463,15 @@ transient input method (@pxref{transient input method}) with
|
||||
@kbd{C-x \} (@code{isearch-transient-input-method}) to insert a single
|
||||
character to the search string using an input method, and
|
||||
automatically disable the input method afterwards.
|
||||
@end itemize
|
||||
|
||||
@item
|
||||
@findex isearch-char-by-name
|
||||
@kindex C-x 8 RET @r{(Incremental Search)}
|
||||
Type @kbd{C-x 8 @key{RET}} (@code{isearch-char-by-name}), followed by
|
||||
a Unicode name or code-point in hex. This adds the specified
|
||||
character into the search string, similar to the usual
|
||||
@code{insert-char} command (@pxref{Inserting Text}).
|
||||
@end itemize
|
||||
|
||||
@findex isearch-emoji-by-name
|
||||
@kindex C-x 8 e RET @r{(Incremental Search)}
|
||||
|
@ -8438,13 +8438,14 @@ displayed in the echo area.
|
||||
@end defun
|
||||
|
||||
@cindex system tooltips
|
||||
@vindex x-gtk-use-system-tooltips
|
||||
When Emacs is built with GTK+ support, it by default displays tooltips
|
||||
using GTK+ functions, and the appearance of the tooltips is then
|
||||
controlled by GTK+ settings. GTK+ tooltips can be disabled by
|
||||
changing the value of the variable @code{x-gtk-use-system-tooltips} to
|
||||
@code{nil}. The rest of this subsection describes how to control
|
||||
non-GTK+ tooltips, which are presented by Emacs itself.
|
||||
@vindex use-system-tooltips
|
||||
When Emacs is built with the GTK+ toolkit or Haiku windowing support,
|
||||
it by default displays tooltips using toolkit functions, and the
|
||||
appearance of the tooltips is then controlled by by the toolkit's
|
||||
settings. Toolkit-provided tooltips can be disabled by changing the
|
||||
value of the variable @code{use-system-tooltips} to @code{nil}. The
|
||||
rest of this subsection describes how to control non-toolkit tooltips,
|
||||
which are presented by Emacs itself.
|
||||
|
||||
@cindex tooltip frames
|
||||
Tooltips are displayed in special frames called tooltip frames, which
|
||||
|
@ -1231,6 +1231,7 @@ Text
|
||||
* Decompression:: Dealing with compressed data.
|
||||
* Base 64:: Conversion to or from base 64 encoding.
|
||||
* Checksum/Hash:: Computing cryptographic hashes.
|
||||
* Suspicious Text:: Determining whether a string is suspicious.
|
||||
* GnuTLS Cryptography:: Cryptographic algorithms imported from GnuTLS.
|
||||
* Database:: Interacting with an SQL database.
|
||||
* Parsing HTML/XML:: Parsing HTML and XML.
|
||||
|
@ -3154,10 +3154,8 @@ raises @var{frame} above all other child frames of its parent.
|
||||
@deffn Command lower-frame &optional frame
|
||||
This function lowers frame @var{frame} (default, the selected frame)
|
||||
below all other frames belonging to the same or a higher z-group as
|
||||
@var{frame}.@footnote{Lowering frames is not supported on Haiku, due
|
||||
to limitations imposed by the system.} If @var{frame} is a child
|
||||
frame (@pxref{Child Frames}), this lowers @var{frame} below all other
|
||||
child frames of its parent.
|
||||
@var{frame}. If @var{frame} is a child frame (@pxref{Child Frames}),
|
||||
this lowers @var{frame} below all other child frames of its parent.
|
||||
@end deffn
|
||||
|
||||
@defun frame-restack frame1 frame2 &optional above
|
||||
|
@ -59,6 +59,7 @@ the character after point.
|
||||
* Decompression:: Dealing with compressed data.
|
||||
* Base 64:: Conversion to or from base 64 encoding.
|
||||
* Checksum/Hash:: Computing cryptographic hashes.
|
||||
* Suspicious Text:: Determining whether a string is suspicious.
|
||||
* GnuTLS Cryptography:: Cryptographic algorithms imported from GnuTLS.
|
||||
* Database:: Interacting with an SQL database.
|
||||
* Parsing HTML/XML:: Parsing HTML and XML.
|
||||
@ -4943,6 +4944,92 @@ It should be somewhat more efficient on larger buffers than
|
||||
@c according to what we find useful.
|
||||
@end defun
|
||||
|
||||
@node Suspicious Text
|
||||
@section Suspicious Text
|
||||
@cindex suspicious text
|
||||
@cindex insecure text
|
||||
@cindex security vulnerabilities in text
|
||||
|
||||
Emacs can display text from many external sources, like email and Web
|
||||
sites. Attackers may attempt to confuse the user reading this text by
|
||||
using obfuscated @acronym{URL}s or email addresses, and tricking the
|
||||
user into visiting a web page they didn't intend to visit, or sending
|
||||
an email to the wrong address.
|
||||
|
||||
This usually involves using characters from scripts that visually look
|
||||
like @acronym{ASCII} characters (i.e., are homoglyphs), but there are
|
||||
also other techniques used, like using bidirectional overrides, or
|
||||
having an @acronym{HTML} link text that says one thing, while the
|
||||
underlying @acronym{URL} points somewhere else.
|
||||
|
||||
@cindex suspicious text strings
|
||||
To help identify these @dfn{suspicious text strings}, Emacs provides a
|
||||
library to do a number of checks on text. (See
|
||||
@url{https://www.unicode.org/reports/tr39/, UTS #39: Unicode Security
|
||||
Mechanisms} for the rationale behind the checks that are available and
|
||||
more details about them.) Packages that present data that might be
|
||||
suspicious should use this library to flag suspicious text on display.
|
||||
|
||||
@vindex textsec-check
|
||||
@defun textsec-suspicious-p object type
|
||||
This function is the high-level interface function that packages
|
||||
should use. It respects the @code{textsec-check} user option, which
|
||||
allows the user to disable the checks.
|
||||
|
||||
This function checks @var{object} (whose data type depends on
|
||||
@var{type}) to see if it looks suspicious when interpreted as a thing
|
||||
of @var{type}. The available types and the corresponding @var{object}
|
||||
data types are:
|
||||
|
||||
@table @code
|
||||
@item domain
|
||||
Check whether a domain (e.g., @samp{www.gnu.org} looks suspicious.
|
||||
@var{object} should be a string, the domain name.
|
||||
|
||||
@item url
|
||||
Check whether an @acronym{URL} (e.g., @samp{http://gnu.org/foo/bar})
|
||||
looks suspicious. @var{object} should be a string, the @acronym{URL}
|
||||
to check.
|
||||
|
||||
@item link
|
||||
Check whether an @acronym{HTML} link (e.g., @samp{<a
|
||||
href='http://gnu.org'>fsf.org</a>} looks suspicious. In this case,
|
||||
@var{object} should be a @code{cons} cell where the @code{car} is the
|
||||
@acronym{URL} string, and the @code{cdr} is the link text. The link
|
||||
is deemed suspicious if the link text contains a domain name, and that
|
||||
domain name points to something other than the @acronym{URL}.
|
||||
|
||||
@item email-address
|
||||
Check whether an email address (e.g., @samp{foo@@example.org}) looks
|
||||
suspicious. @var{object} should be a string.
|
||||
|
||||
@item local-address
|
||||
Check whether the local part of an email address (the bit before the
|
||||
@samp{@@} sign) looks suspicious. @var{object} should be a string.
|
||||
|
||||
@item name
|
||||
Check whether a name (used in an email address header) looks
|
||||
suspicious. @var{object} should be a string.
|
||||
|
||||
@item email-address-header
|
||||
Check whether a full RFC2822 email address header (e.g.,
|
||||
@samp{=?utf-8?Q?=C3=81?= <foo@@example.com>}) looks suspicious.
|
||||
@var{object} should be a string.
|
||||
@end table
|
||||
|
||||
If @var{object} is suspicious, this function returns a string that
|
||||
explains why it is suspicious. If @var{object} is not suspicious, the
|
||||
function returns @code{nil}.
|
||||
@end defun
|
||||
|
||||
@vindex textsec-suspicious@r{ (face)}
|
||||
If the text is suspicious, the application should mark the suspicious
|
||||
text with the @code{textsec-suspicious} face, and make the explanation
|
||||
returned by @code{textsec-suspicious-p} available to the user in some way
|
||||
(for example, in a tooltip). The application might also prompt the
|
||||
user for confirmation before taking any action on a suspicious string
|
||||
(like sending an email to a suspicious email address).
|
||||
|
||||
@node GnuTLS Cryptography
|
||||
@section GnuTLS Cryptography
|
||||
@cindex MD5 checksum
|
||||
|
@ -444,8 +444,9 @@ emacs -batch -l ert -l my-tests.el \
|
||||
@vindex EMACS_TEST_VERBOSE@r{, environment variable}
|
||||
By default, ERT test failure summaries are quite brief in batch
|
||||
mode---only the names of the failed tests are listed. If the
|
||||
@env{EMACS_TEST_VERBOSE} environment variable is set, the failure
|
||||
summaries will also include the data from the failing test.
|
||||
@env{EMACS_TEST_VERBOSE} environment variable is set and is non-empty,
|
||||
the failure summaries will also include the data from the failing
|
||||
test.
|
||||
|
||||
@vindex EMACS_TEST_JUNIT_REPORT@r{, environment variable}
|
||||
ERT can produce JUnit test reports in batch mode. If the environment
|
||||
|
@ -407,9 +407,16 @@ Summarize disk usage for each file.
|
||||
|
||||
@item echo
|
||||
@cmindex echo
|
||||
Echoes its input. If @code{eshell-plain-echo-behavior} is
|
||||
non-@code{nil}, @command{echo} will try to behave more like a plain
|
||||
shell's @command{echo}.
|
||||
Echoes its input. By default, this prints in a Lisp-friendly fashion
|
||||
(so that the value is useful to a Lisp command using the result of
|
||||
@command{echo} as an argument). If a single argument is passed,
|
||||
@command{echo} prints that; if multiple arguments are passed, it
|
||||
prints a list of all the arguments; otherwise, it prints the empty
|
||||
string.
|
||||
|
||||
If @code{eshell-plain-echo-behavior} is non-@code{nil}, @command{echo}
|
||||
will try to behave more like a plain shell's @command{echo}, printing
|
||||
each argument as a string, separated by a space.
|
||||
|
||||
@item env
|
||||
@cmindex env
|
||||
|
@ -14838,12 +14838,17 @@ mail belongs in that group.
|
||||
The last of these groups should always be a general one, and the regular
|
||||
expression should @emph{always} be @samp{""} so that it matches any mails
|
||||
that haven't been matched by any of the other regexps. (These rules are
|
||||
processed from the beginning of the alist toward the end. The first rule
|
||||
to make a match will ``win'', unless you have crossposting enabled. In
|
||||
that case, all matching rules will ``win''.) If no rule matched, the mail
|
||||
will end up in the @samp{bogus} group. When new groups are created by
|
||||
splitting mail, you may want to run @code{gnus-group-find-new-groups} to
|
||||
see the new groups. This also applies to the @samp{bogus} group.
|
||||
processed from the beginning of the alist toward the end.
|
||||
|
||||
If multiple rules match (excluding the general @samp{""} group), mail
|
||||
is crossposted to all these groups. However, if
|
||||
@code{nnmail-crosspost} is set to @code{nil}, the first rule to make a
|
||||
match will ``win''.
|
||||
|
||||
If no rule matched, the mail will end up in the @samp{bogus} group.
|
||||
When new groups are created by splitting mail, you may want to run
|
||||
@code{gnus-group-find-new-groups} to see the new groups. This also
|
||||
applies to the @samp{bogus} group.
|
||||
|
||||
If you like to tinker with this yourself, you can set this variable to a
|
||||
function of your choice. This function will be called without any
|
||||
|
77
etc/NEWS
77
etc/NEWS
@ -104,6 +104,11 @@ files that were compiled with an old EIEIO (Emacs<25).
|
||||
** 'C-x 8 .' has been moved to 'C-x 8 . .'.
|
||||
This is to open up the 'C-x 8 .' map to bind further characters there.
|
||||
|
||||
---
|
||||
** 'source' and '.' in Eshell no longer accept the '--help' option.
|
||||
This is for compatibility with the shell versions of these commands,
|
||||
which don't handle options like '--help' in any special way.
|
||||
|
||||
|
||||
* Changes in Emacs 29.1
|
||||
|
||||
@ -154,6 +159,15 @@ methods.
|
||||
This controls whether or not GTK input methods are used by Emacs,
|
||||
instead of XIM input methods.
|
||||
|
||||
+++
|
||||
** New user option 'use-system-tooltips'.
|
||||
This controls whether to use the toolkit tooltips, or Emacs's own
|
||||
native implementation of tooltips as small frames. This option is
|
||||
only meaningful if Emacs was built with GTK+ or Haiku support, and
|
||||
defaults to t, which makes Emacs use the toolkit tooltips. The
|
||||
existing GTK-specific option 'x-gtk-use-system-tooltips' is now an
|
||||
alias of this new option.
|
||||
|
||||
---
|
||||
** New minor mode 'pixel-scroll-precision-mode'.
|
||||
When enabled, and if your mouse supports it, you can scroll the
|
||||
@ -243,6 +257,16 @@ These will take you (respectively) to the next and previous "page".
|
||||
---
|
||||
*** 'describe-char' now also outputs the name of emoji combinations.
|
||||
|
||||
** Outline Mode
|
||||
|
||||
*** Support for a default visibility state.
|
||||
Customize the option 'outline-default-state' to define what headings
|
||||
are visible when the mode is set. When equal to a number, the option
|
||||
'outline-default-rules' determines the visibility of the subtree
|
||||
starting at the corresponding level. Values are provided to show
|
||||
a heading subtree unless the heading match a regexp, or its subtree
|
||||
has long lines or is long.
|
||||
|
||||
** Outline Minor Mode
|
||||
|
||||
+++
|
||||
@ -326,7 +350,7 @@ are met. The conditions are given by the argument, which can be
|
||||
These forms now indent like this:
|
||||
|
||||
(cl-flet ((bla (x)
|
||||
(* x x)))
|
||||
(* x x)))
|
||||
(bla 42))
|
||||
|
||||
This change also affects 'cl-macrolet', 'cl-flet*' and
|
||||
@ -823,6 +847,10 @@ the Netscape web browser was released in February, 2008.
|
||||
This support has been obsolete since Emacs 25.1. The final version of
|
||||
the Galeon web browser was released in September, 2008.
|
||||
|
||||
** Ruby Mode
|
||||
|
||||
*** New user option 'ruby-toggle-block-space-before-parameters'.
|
||||
|
||||
** Miscellaneous
|
||||
|
||||
---
|
||||
@ -938,9 +966,30 @@ characters in the range U+0080..U+00FF as substitutes for single bytes
|
||||
in the range 128..255, but signal an error for all multibyte characters.
|
||||
The input must be encoded text.
|
||||
|
||||
+++
|
||||
** The 'clone-indirect-buffer-hook' is now run by 'make-indirect-buffer'.
|
||||
It was previously only run by 'clone-indirect-buffer' and
|
||||
'clone-indirect-buffer-other-window'. Since 'make-indirect-buffer' is
|
||||
called by both of these, the hook is now run by all 3 of these
|
||||
functions.
|
||||
|
||||
|
||||
* Lisp Changes in Emacs 29.1
|
||||
|
||||
--
|
||||
** The variable 'polling-period' now accepts floating point values.
|
||||
This means Emacs can now poll for input during Lisp execution more
|
||||
frequently than once in a second.
|
||||
|
||||
--
|
||||
** New function 'bidi-string-strip-control-characters'.
|
||||
This utility function is meant for displaying strings when it's
|
||||
essential that there's no bidirectional context.
|
||||
|
||||
---
|
||||
** The Gnus range functions have been moved to a new library, range.el.
|
||||
All the old names have been made obsolete.
|
||||
|
||||
+++
|
||||
** New function 'function-alias-p'.
|
||||
This predicate says whether an object is a function alias, and if it
|
||||
@ -980,6 +1029,32 @@ This event is sent when a user peforms a pinch gesture on a touchpad,
|
||||
which is comprised of placing two fingers on the touchpad and moving
|
||||
them towards or away from each other.
|
||||
|
||||
** Text security and suspiciousness
|
||||
|
||||
+++
|
||||
*** New library textsec.el.
|
||||
This library contains a number of checks for whether a string is
|
||||
"suspicious". This usually means that the string contains characters
|
||||
that have glyphs that can be confused with other, more commonly used
|
||||
glyphs, or contain bidirectional (or other) formatting characters that
|
||||
may be used to confuse a user.
|
||||
|
||||
+++
|
||||
*** New user option 'textsec-check'.
|
||||
If non-nil (which is the default), Emacs packages that are vulnerable
|
||||
to attackers trying to confuse the users will use the textsec library
|
||||
to mark suspicious text. For instance shr/eww will mark suspicious
|
||||
URLs and links, Gnus will mark suspicious From addresses, and
|
||||
Message mode will query the user if the user is sending mail to a
|
||||
suspicious address. If this variable is nil, these checks aren't
|
||||
performed.
|
||||
|
||||
+++
|
||||
*** New function 'textsec-suspicious-p'.
|
||||
This is the main function Emacs applications should be using to check
|
||||
whether a string is suspicious. It heeds the 'textsec-check' user
|
||||
option.
|
||||
|
||||
** Keymaps and key definitions
|
||||
|
||||
+++
|
||||
|
@ -1304,6 +1304,13 @@ and then Alt-F7). A bug for it is here:
|
||||
https://bugs.launchpad.net/ubuntu/+source/metacity/+bug/231034.
|
||||
Note that a permanent fix seems to be to disable "assistive technologies".
|
||||
|
||||
*** Enlightenment: Frames not redrawn after switching virtual desktops
|
||||
|
||||
With Enlightenment version 0.25, Emacs frames may no be redrawn orderly
|
||||
after switching back from another virtual desktop. Setting the variable
|
||||
'x-set-frame-visibility-more-laxly' to one of 'focus-in', 'expose' or
|
||||
't' should fix this.
|
||||
|
||||
*** Gnome: Emacs receives input directly from the keyboard, bypassing XIM.
|
||||
|
||||
This seems to happen when gnome-settings-daemon version 2.12 or later
|
||||
|
@ -29,6 +29,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include <Application.h>
|
||||
#include <Catalog.h>
|
||||
#include <Roster.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Rect.h>
|
||||
#include <View.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -79,11 +82,25 @@ main (int argc, char **argv)
|
||||
BApplication app ("application/x-vnd.GNU-emacs-resource-helper");
|
||||
BFile file;
|
||||
BBitmap *icon;
|
||||
BBitmap scale32 (BRect (0, 0, 31, 31), B_RGBA32, true);
|
||||
BBitmap scale16 (BRect (0, 0, 15, 15), B_RGBA32, true);
|
||||
BAppFileInfo info;
|
||||
status_t code;
|
||||
struct version_info vinfo;
|
||||
char *v = strdup (PACKAGE_VERSION);
|
||||
|
||||
if (scale32.InitCheck () != B_OK
|
||||
|| scale16.InitCheck () != B_OK)
|
||||
{
|
||||
fprintf (stderr, "Bitmap initialization ran out of memory\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
BView scale32view (scale32.Bounds (), NULL,
|
||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
BView scale16view (scale16.Bounds (), NULL,
|
||||
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
printf ("be-resources ICON FILE: make FILE appropriate for Emacs.\n");
|
||||
@ -117,8 +134,24 @@ main (int argc, char **argv)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
info.SetIcon (icon, B_MINI_ICON);
|
||||
info.SetIcon (icon, B_LARGE_ICON);
|
||||
scale32.AddChild (&scale32view);
|
||||
scale16.AddChild (&scale16view);
|
||||
|
||||
if (!scale32view.LockLooper ()
|
||||
|| !scale16view.LockLooper ())
|
||||
{
|
||||
fprintf (stderr, "Failed to lock bitmap looper\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
scale32view.DrawBitmapAsync (icon, scale32.Bounds ());
|
||||
scale16view.DrawBitmapAsync (icon, scale16.Bounds ());
|
||||
|
||||
scale32view.Sync ();
|
||||
scale16view.Sync ();
|
||||
|
||||
info.SetIcon (&scale16, B_MINI_ICON);
|
||||
info.SetIcon (&scale32, B_LARGE_ICON);
|
||||
info.SetSignature ("application/x-vnd.GNU-emacs");
|
||||
|
||||
v = strtok (v, ".");
|
||||
@ -140,5 +173,5 @@ main (int argc, char **argv)
|
||||
|
||||
info.SetVersionInfo (&vinfo, B_APP_VERSION_KIND);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
@ -1925,7 +1925,15 @@ matching_regexp (void)
|
||||
*--s = *--t;
|
||||
|
||||
if (*s == '"' || *s == '\\')
|
||||
*--s = '\\';
|
||||
{
|
||||
if (s > matching_regexp_buffer)
|
||||
*--s = '\\';
|
||||
else
|
||||
{
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*(matching_regexp_end_buf - 1) = '\0';
|
||||
|
@ -77,6 +77,8 @@ AUTOGENEL = ${loaddefs} ${srcdir}/cus-load.el ${srcdir}/finder-inf.el \
|
||||
# Set load-prefer-newer for the benefit of the non-bootstrappers.
|
||||
BYTE_COMPILE_FLAGS = \
|
||||
--eval '(setq load-prefer-newer t)' $(BYTE_COMPILE_EXTRA_FLAGS)
|
||||
# ... but we must prefer .elc files for those in the early bootstrap.
|
||||
compile-first: BYTE_COMPILE_FLAGS = $(BYTE_COMPILE_EXTRA_FLAGS)
|
||||
|
||||
# Files to compile before others during a bootstrap. This is done to
|
||||
# speed up the bootstrap process. They're ordered by size, so we use
|
||||
@ -303,9 +305,23 @@ endif
|
||||
# An old-fashioned suffix rule, which, according to the GNU Make manual,
|
||||
# cannot have prerequisites.
|
||||
ifeq ($(HAVE_NATIVE_COMP),yes)
|
||||
ifeq ($(ANCIENT),yes)
|
||||
# The first compilation of compile-first, using an interpreted compiler:
|
||||
# The resulting .elc files get given a date of 1971-01-01 so that their
|
||||
# date stamp is earlier than the source files, causing these to be compiled
|
||||
# into native code at the second recursive invocation of this $(MAKE),
|
||||
# using these .elc's. This is faster than just compiling the native code
|
||||
# directly using the interpreted compile-first files. (Note: 1970-01-01
|
||||
# fails on some systems.)
|
||||
.el.elc:
|
||||
$(AM_V_ELC)$(emacs) $(BYTE_COMPILE_FLAGS) \
|
||||
-l comp -f batch-byte-compile $<
|
||||
touch -t 197101010000 $@
|
||||
else
|
||||
.el.elc:
|
||||
$(AM_V_ELC)$(emacs) $(BYTE_COMPILE_FLAGS) \
|
||||
-l comp -f batch-byte+native-compile $<
|
||||
endif
|
||||
else
|
||||
.el.elc:
|
||||
$(AM_V_ELC)$(emacs) $(BYTE_COMPILE_FLAGS) -f batch-byte-compile $<
|
||||
|
140
lisp/cus-face.el
140
lisp/cus-face.el
@ -46,7 +46,7 @@
|
||||
;;; Face attributes.
|
||||
|
||||
(defconst custom-face-attributes
|
||||
'((:family
|
||||
`((:family
|
||||
(string :tag "Font Family"
|
||||
:help-echo "Font family or fontset alias name."))
|
||||
|
||||
@ -148,29 +148,29 @@
|
||||
(const :tag "At Bottom Of Text" t)
|
||||
(integer :tag "Pixels Above Bottom Of Text"))))
|
||||
;; filter to make value suitable for customize
|
||||
(lambda (real-value)
|
||||
(and real-value
|
||||
(let ((color
|
||||
(or (and (consp real-value) (plist-get real-value :color))
|
||||
(and (stringp real-value) real-value)
|
||||
'foreground-color))
|
||||
(style
|
||||
(or (and (consp real-value) (plist-get real-value :style))
|
||||
'line))
|
||||
(position (and (consp real-value)
|
||||
(plist-get real-value :style))))
|
||||
(list :color color :style style :position position))))
|
||||
,(lambda (real-value)
|
||||
(and real-value
|
||||
(let ((color
|
||||
(or (and (consp real-value) (plist-get real-value :color))
|
||||
(and (stringp real-value) real-value)
|
||||
'foreground-color))
|
||||
(style
|
||||
(or (and (consp real-value) (plist-get real-value :style))
|
||||
'line))
|
||||
(position (and (consp real-value)
|
||||
(plist-get real-value :style))))
|
||||
(list :color color :style style :position position))))
|
||||
;; filter to make customized-value suitable for storing
|
||||
(lambda (cus-value)
|
||||
(and cus-value
|
||||
(let ((color (plist-get cus-value :color))
|
||||
(style (plist-get cus-value :style))
|
||||
(position (plist-get cus-value :position)))
|
||||
(cond ((and (eq style 'line) (not position))
|
||||
;; Use simple value for default style
|
||||
(if (eq color 'foreground-color) t color))
|
||||
(t
|
||||
`(:color ,color :style ,style :position ,position)))))))
|
||||
,(lambda (cus-value)
|
||||
(and cus-value
|
||||
(let ((color (plist-get cus-value :color))
|
||||
(style (plist-get cus-value :style))
|
||||
(position (plist-get cus-value :position)))
|
||||
(cond ((and (eq style 'line) (not position))
|
||||
;; Use simple value for default style
|
||||
(if (eq color 'foreground-color) t color))
|
||||
(t
|
||||
`(:color ,color :style ,style :position ,position)))))))
|
||||
|
||||
(:overline
|
||||
(choice :tag "Overline"
|
||||
@ -206,40 +206,40 @@
|
||||
(const :tag "Flat" flat-button)
|
||||
(const :tag "None" nil))))
|
||||
;; filter to make value suitable for customize
|
||||
(lambda (real-value)
|
||||
(and real-value
|
||||
(let ((lwidth
|
||||
(or (and (consp real-value)
|
||||
(if (listp (cdr real-value))
|
||||
(plist-get real-value :line-width)
|
||||
real-value))
|
||||
(and (integerp real-value) real-value)
|
||||
'(1 . 1)))
|
||||
(color
|
||||
(or (and (consp real-value) (plist-get real-value :color))
|
||||
(and (stringp real-value) real-value)
|
||||
nil))
|
||||
(style
|
||||
(and (consp real-value) (plist-get real-value :style))))
|
||||
(if (integerp lwidth)
|
||||
(setq lwidth (cons (abs lwidth) lwidth)))
|
||||
(list :line-width lwidth :color color :style style))))
|
||||
,(lambda (real-value)
|
||||
(and real-value
|
||||
(let ((lwidth
|
||||
(or (and (consp real-value)
|
||||
(if (listp (cdr real-value))
|
||||
(plist-get real-value :line-width)
|
||||
real-value))
|
||||
(and (integerp real-value) real-value)
|
||||
'(1 . 1)))
|
||||
(color
|
||||
(or (and (consp real-value) (plist-get real-value :color))
|
||||
(and (stringp real-value) real-value)
|
||||
nil))
|
||||
(style
|
||||
(and (consp real-value) (plist-get real-value :style))))
|
||||
(if (integerp lwidth)
|
||||
(setq lwidth (cons (abs lwidth) lwidth)))
|
||||
(list :line-width lwidth :color color :style style))))
|
||||
;; filter to make customized-value suitable for storing
|
||||
(lambda (cus-value)
|
||||
(and cus-value
|
||||
(let ((lwidth (plist-get cus-value :line-width))
|
||||
(color (plist-get cus-value :color))
|
||||
(style (plist-get cus-value :style)))
|
||||
(cond ((and (null color) (null style))
|
||||
lwidth)
|
||||
((and (null lwidth) (null style))
|
||||
;; actually can't happen, because LWIDTH is always an int
|
||||
color)
|
||||
(t
|
||||
;; Keep as a plist, but remove null entries
|
||||
(nconc (and lwidth `(:line-width ,lwidth))
|
||||
(and color `(:color ,color))
|
||||
(and style `(:style ,style)))))))))
|
||||
,(lambda (cus-value)
|
||||
(and cus-value
|
||||
(let ((lwidth (plist-get cus-value :line-width))
|
||||
(color (plist-get cus-value :color))
|
||||
(style (plist-get cus-value :style)))
|
||||
(cond ((and (null color) (null style))
|
||||
lwidth)
|
||||
((and (null lwidth) (null style))
|
||||
;; actually can't happen, because LWIDTH is always an int
|
||||
color)
|
||||
(t
|
||||
;; Keep as a plist, but remove null entries
|
||||
(nconc (and lwidth `(:line-width ,lwidth))
|
||||
(and color `(:color ,color))
|
||||
(and style `(:style ,style)))))))))
|
||||
|
||||
(:inverse-video
|
||||
(choice :tag "Inverse-video"
|
||||
@ -276,18 +276,18 @@
|
||||
:help-echo "List of faces to inherit attributes from."
|
||||
(face :Tag "Face" default))
|
||||
;; filter to make value suitable for customize
|
||||
(lambda (real-value)
|
||||
(cond ((or (null real-value) (eq real-value 'unspecified))
|
||||
nil)
|
||||
((symbolp real-value)
|
||||
(list real-value))
|
||||
(t
|
||||
real-value)))
|
||||
,(lambda (real-value)
|
||||
(cond ((or (null real-value) (eq real-value 'unspecified))
|
||||
nil)
|
||||
((symbolp real-value)
|
||||
(list real-value))
|
||||
(t
|
||||
real-value)))
|
||||
;; filter to make customized-value suitable for storing
|
||||
(lambda (cus-value)
|
||||
(if (and (consp cus-value) (null (cdr cus-value)))
|
||||
(car cus-value)
|
||||
cus-value))))
|
||||
,(lambda (cus-value)
|
||||
(if (and (consp cus-value) (null (cdr cus-value)))
|
||||
(car cus-value)
|
||||
cus-value))))
|
||||
|
||||
"Alist of face attributes.
|
||||
|
||||
@ -329,12 +329,12 @@ If FRAME is nil, use the global defaults for FACE."
|
||||
"Apply a list of face specs for user customizations.
|
||||
This works by calling `custom-theme-set-faces' for the `user'
|
||||
theme, a special theme referring to settings made via Customize.
|
||||
The arguments should be a list where each entry has the form:
|
||||
The arguments ARGS should be a list where each entry has the form:
|
||||
|
||||
(FACE SPEC [NOW [COMMENT]])
|
||||
|
||||
See the documentation of `custom-theme-set-faces' for details."
|
||||
(apply 'custom-theme-set-faces 'user args))
|
||||
(apply #'custom-theme-set-faces 'user args))
|
||||
|
||||
(defun custom-theme-set-faces (theme &rest args)
|
||||
"Apply a list of face specs associated with theme THEME.
|
||||
@ -419,7 +419,7 @@ Each of the arguments ARGS has this form:
|
||||
(FACE FROM-THEME)
|
||||
|
||||
This means reset FACE to its value in FROM-THEME."
|
||||
(apply 'custom-theme-reset-faces 'user args))
|
||||
(apply #'custom-theme-reset-faces 'user args))
|
||||
|
||||
(define-obsolete-function-alias 'custom-facep #'facep "28.1")
|
||||
|
||||
|
@ -356,6 +356,7 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of
|
||||
(const :tag "Iconify" t))
|
||||
"26.1")
|
||||
(tooltip-reuse-hidden-frame tooltip boolean "26.1")
|
||||
(use-system-tooltips tooltip boolean "29.1")
|
||||
;; fringe.c
|
||||
(overflow-newline-into-fringe fringe boolean)
|
||||
;; image.c
|
||||
@ -369,7 +370,7 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of
|
||||
(auto-save-timeout auto-save (choice (const :tag "off" nil)
|
||||
(integer :format "%v")))
|
||||
(echo-keystrokes minibuffer number)
|
||||
(polling-period keyboard integer)
|
||||
(polling-period keyboard float)
|
||||
(double-click-time mouse (restricted-sexp
|
||||
:match-alternatives (integerp 'nil 't)))
|
||||
(double-click-fuzz mouse integer "22.1")
|
||||
|
@ -1189,7 +1189,7 @@ is named like ODF with the extension turned to pdf."
|
||||
"Convert PDF-PS to PNG asynchronously."
|
||||
(funcall
|
||||
(pcase doc-view-doc-type
|
||||
('pdf doc-view-pdf->png-converter-function)
|
||||
((or 'pdf 'odf) doc-view-pdf->png-converter-function)
|
||||
('djvu #'doc-view-djvu->tiff-converter-ddjvu)
|
||||
(_ #'doc-view-ps->png-converter-ghostscript))
|
||||
pdf-ps png nil
|
||||
|
@ -340,7 +340,7 @@ put the output in."
|
||||
(t
|
||||
(let ((doc-string-elt (function-get (car-safe form) 'doc-string-elt))
|
||||
(outbuf autoload-print-form-outbuf))
|
||||
(if (and doc-string-elt (stringp (nth doc-string-elt form)))
|
||||
(if (and (numberp doc-string-elt) (stringp (nth doc-string-elt form)))
|
||||
;; We need to hack the printing because the
|
||||
;; doc-string must be printed specially for
|
||||
;; make-docfile (sigh).
|
||||
@ -410,7 +410,7 @@ FILE's name."
|
||||
";; version-control: never\n"
|
||||
";; no-byte-compile: t\n" ;; #$ is byte-compiled into nil.
|
||||
";; no-update-autoloads: t\n"
|
||||
";; coding: utf-8\n"
|
||||
";; coding: utf-8-emacs-unix\n"
|
||||
";; End:\n"
|
||||
";;; " basename
|
||||
" ends here\n")))
|
||||
|
@ -617,8 +617,8 @@ Each element is (INDEX . VALUE)")
|
||||
"Hash byte-code -> byte-to-native-lambda.")
|
||||
(defvar byte-to-native-top-level-forms nil
|
||||
"List of top level forms.")
|
||||
(defvar byte-to-native-output-file nil
|
||||
"Temporary file containing the byte-compilation output.")
|
||||
(defvar byte-to-native-output-buffer-file nil
|
||||
"Pair holding byte-compilation output buffer, elc filename.")
|
||||
(defvar byte-to-native-plist-environment nil
|
||||
"To spill `overriding-plist-environment'.")
|
||||
|
||||
@ -1986,6 +1986,42 @@ If compilation is needed, this functions returns the result of
|
||||
(defvar byte-compile-level 0 ; bug#13787
|
||||
"Depth of a recursive byte compilation.")
|
||||
|
||||
(defun byte-write-target-file (buffer target-file)
|
||||
"Write BUFFER into TARGET-FILE."
|
||||
(with-current-buffer buffer
|
||||
;; We must disable any code conversion here.
|
||||
(let* ((coding-system-for-write 'no-conversion)
|
||||
;; Write to a tempfile so that if another Emacs
|
||||
;; process is trying to load target-file (eg in a
|
||||
;; parallel bootstrap), it does not risk getting a
|
||||
;; half-finished file. (Bug#4196)
|
||||
(tempfile
|
||||
(make-temp-file (when (file-writable-p target-file)
|
||||
(expand-file-name target-file))))
|
||||
(default-modes (default-file-modes))
|
||||
(temp-modes (logand default-modes #o600))
|
||||
(desired-modes (logand default-modes #o666))
|
||||
(kill-emacs-hook
|
||||
(cons (lambda () (ignore-errors
|
||||
(delete-file tempfile)))
|
||||
kill-emacs-hook)))
|
||||
(unless (= temp-modes desired-modes)
|
||||
(set-file-modes tempfile desired-modes 'nofollow))
|
||||
(write-region (point-min) (point-max) tempfile nil 1)
|
||||
;; This has the intentional side effect that any
|
||||
;; hard-links to target-file continue to
|
||||
;; point to the old file (this makes it possible
|
||||
;; for installed files to share disk space with
|
||||
;; the build tree, without causing problems when
|
||||
;; emacs-lisp files in the build tree are
|
||||
;; recompiled). Previously this was accomplished by
|
||||
;; deleting target-file before writing it.
|
||||
(if byte-native-compiling
|
||||
;; Defer elc final renaming.
|
||||
(setf byte-to-native-output-buffer-file
|
||||
(cons tempfile target-file))
|
||||
(rename-file tempfile target-file t)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun byte-compile-file (filename &optional load)
|
||||
"Compile a file of Lisp code named FILENAME into a file of byte code.
|
||||
@ -2020,176 +2056,148 @@ See also `emacs-lisp-byte-compile-and-load'."
|
||||
|
||||
;; Force logging of the file name for each file compiled.
|
||||
(setq byte-compile-last-logged-file nil)
|
||||
(prog1
|
||||
(let ((byte-compile-current-file filename)
|
||||
(byte-compile-current-group nil)
|
||||
(set-auto-coding-for-load t)
|
||||
(byte-compile--seen-defvars nil)
|
||||
(byte-compile--known-dynamic-vars
|
||||
(byte-compile--load-dynvars (getenv "EMACS_DYNVARS_FILE")))
|
||||
target-file input-buffer output-buffer
|
||||
byte-compile-dest-file byte-compiler-error-flag)
|
||||
(setq target-file (byte-compile-dest-file filename))
|
||||
(setq byte-compile-dest-file target-file)
|
||||
(with-current-buffer
|
||||
;; It would be cleaner to use a temp buffer, but if there was
|
||||
;; an error, we leave this buffer around for diagnostics.
|
||||
;; Its name is documented in the lispref.
|
||||
(setq input-buffer (get-buffer-create
|
||||
(concat " *Compiler Input*"
|
||||
(if (zerop byte-compile-level) ""
|
||||
(format "-%s" byte-compile-level)))))
|
||||
(erase-buffer)
|
||||
(setq buffer-file-coding-system nil)
|
||||
;; Always compile an Emacs Lisp file as multibyte
|
||||
;; unless the file itself forces unibyte with -*-coding: raw-text;-*-
|
||||
(set-buffer-multibyte t)
|
||||
(insert-file-contents filename)
|
||||
;; Mimic the way after-insert-file-set-coding can make the
|
||||
;; buffer unibyte when visiting this file.
|
||||
(when (or (eq last-coding-system-used 'no-conversion)
|
||||
(eq (coding-system-type last-coding-system-used) 5))
|
||||
;; For coding systems no-conversion and raw-text...,
|
||||
;; edit the buffer as unibyte.
|
||||
(set-buffer-multibyte nil))
|
||||
;; Run hooks including the uncompression hook.
|
||||
;; If they change the file name, then change it for the output also.
|
||||
(let ((buffer-file-name filename)
|
||||
(dmm (default-value 'major-mode))
|
||||
;; Ignore unsafe local variables.
|
||||
;; We only care about a few of them for our purposes.
|
||||
(enable-local-variables :safe)
|
||||
(enable-local-eval nil))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq-default major-mode 'emacs-lisp-mode)
|
||||
;; Arg of t means don't alter enable-local-variables.
|
||||
(delay-mode-hooks (normal-mode t)))
|
||||
(setq-default major-mode dmm))
|
||||
;; There may be a file local variable setting (bug#10419).
|
||||
(setq buffer-read-only nil
|
||||
filename buffer-file-name))
|
||||
;; Don't inherit lexical-binding from caller (bug#12938).
|
||||
(unless (local-variable-p 'lexical-binding)
|
||||
(setq-local lexical-binding nil))
|
||||
;; Set the default directory, in case an eval-when-compile uses it.
|
||||
(setq default-directory (file-name-directory filename)))
|
||||
;; Check if the file's local variables explicitly specify not to
|
||||
;; compile this file.
|
||||
(if (with-current-buffer input-buffer no-byte-compile)
|
||||
(progn
|
||||
;; (message "%s not compiled because of `no-byte-compile: %s'"
|
||||
;; (byte-compile-abbreviate-file filename)
|
||||
;; (with-current-buffer input-buffer no-byte-compile))
|
||||
(when (and target-file (file-exists-p target-file))
|
||||
(message "%s deleted because of `no-byte-compile: %s'"
|
||||
(byte-compile-abbreviate-file target-file)
|
||||
(buffer-local-value 'no-byte-compile input-buffer))
|
||||
(condition-case nil (delete-file target-file) (error nil)))
|
||||
;; We successfully didn't compile this file.
|
||||
'no-byte-compile)
|
||||
(when byte-compile-verbose
|
||||
(message "Compiling %s..." filename))
|
||||
;; It is important that input-buffer not be current at this call,
|
||||
;; so that the value of point set in input-buffer
|
||||
;; within byte-compile-from-buffer lingers in that buffer.
|
||||
(setq output-buffer
|
||||
(save-current-buffer
|
||||
(let ((symbols-with-pos-enabled t)
|
||||
(byte-compile-level (1+ byte-compile-level)))
|
||||
(byte-compile-from-buffer input-buffer))))
|
||||
(if byte-compiler-error-flag
|
||||
nil
|
||||
(when byte-compile-verbose
|
||||
(message "Compiling %s...done" filename))
|
||||
(kill-buffer input-buffer)
|
||||
(with-current-buffer output-buffer
|
||||
(when (and target-file
|
||||
(or (not byte-native-compiling)
|
||||
(and byte-native-compiling byte+native-compile)))
|
||||
(goto-char (point-max))
|
||||
(insert "\n") ; aaah, unix.
|
||||
(cond
|
||||
((and (file-writable-p target-file)
|
||||
;; We attempt to create a temporary file in the
|
||||
;; target directory, so the target directory must be
|
||||
;; writable.
|
||||
(file-writable-p
|
||||
(file-name-directory
|
||||
;; Need to expand in case TARGET-FILE doesn't
|
||||
;; include a directory (Bug#45287).
|
||||
(expand-file-name target-file))))
|
||||
;; We must disable any code conversion here.
|
||||
(let* ((coding-system-for-write 'no-conversion)
|
||||
;; Write to a tempfile so that if another Emacs
|
||||
;; process is trying to load target-file (eg in a
|
||||
;; parallel bootstrap), it does not risk getting a
|
||||
;; half-finished file. (Bug#4196)
|
||||
(tempfile
|
||||
(make-temp-file (when (file-writable-p target-file)
|
||||
(expand-file-name target-file))))
|
||||
(default-modes (default-file-modes))
|
||||
(temp-modes (logand default-modes #o600))
|
||||
(desired-modes (logand default-modes #o666))
|
||||
(kill-emacs-hook
|
||||
(cons (lambda () (ignore-errors
|
||||
(delete-file tempfile)))
|
||||
kill-emacs-hook)))
|
||||
(unless (= temp-modes desired-modes)
|
||||
(set-file-modes tempfile desired-modes 'nofollow))
|
||||
(write-region (point-min) (point-max) tempfile nil 1)
|
||||
;; This has the intentional side effect that any
|
||||
;; hard-links to target-file continue to
|
||||
;; point to the old file (this makes it possible
|
||||
;; for installed files to share disk space with
|
||||
;; the build tree, without causing problems when
|
||||
;; emacs-lisp files in the build tree are
|
||||
;; recompiled). Previously this was accomplished by
|
||||
;; deleting target-file before writing it.
|
||||
(if byte-native-compiling
|
||||
;; Defer elc final renaming.
|
||||
(setf byte-to-native-output-file
|
||||
(cons tempfile target-file))
|
||||
(rename-file tempfile target-file t)))
|
||||
(or noninteractive
|
||||
byte-native-compiling
|
||||
(message "Wrote %s" target-file)))
|
||||
((file-writable-p target-file)
|
||||
;; In case the target directory isn't writable (see e.g. Bug#44631),
|
||||
;; try writing to the output file directly. We must disable any
|
||||
;; code conversion here.
|
||||
(let ((coding-system-for-write 'no-conversion))
|
||||
(with-file-modes (logand (default-file-modes) #o666)
|
||||
(write-region (point-min) (point-max) target-file nil 1)))
|
||||
(or noninteractive (message "Wrote %s" target-file)))
|
||||
(t
|
||||
;; This is just to give a better error message than write-region
|
||||
(let ((exists (file-exists-p target-file)))
|
||||
(signal (if exists 'file-error 'file-missing)
|
||||
(list "Opening output file"
|
||||
(if exists
|
||||
"Cannot overwrite file"
|
||||
"Directory not writable or nonexistent")
|
||||
target-file))))))
|
||||
(kill-buffer (current-buffer)))
|
||||
(if (and byte-compile-generate-call-tree
|
||||
(or (eq t byte-compile-generate-call-tree)
|
||||
(y-or-n-p (format "Report call tree for %s? "
|
||||
filename))))
|
||||
(save-excursion
|
||||
(display-call-tree filename)))
|
||||
(let ((gen-dynvars (getenv "EMACS_GENERATE_DYNVARS")))
|
||||
(when (and gen-dynvars (not (equal gen-dynvars ""))
|
||||
byte-compile--seen-defvars)
|
||||
(let ((dynvar-file (concat target-file ".dynvars")))
|
||||
(message "Generating %s" dynvar-file)
|
||||
(with-temp-buffer
|
||||
(dolist (var (delete-dups byte-compile--seen-defvars))
|
||||
(insert (format "%S\n" (cons var filename))))
|
||||
(write-region (point-min) (point-max) dynvar-file)))))
|
||||
(if load
|
||||
(load target-file))
|
||||
t)))))
|
||||
(let ((byte-compile-current-file filename)
|
||||
(byte-compile-current-group nil)
|
||||
(set-auto-coding-for-load t)
|
||||
(byte-compile--seen-defvars nil)
|
||||
(byte-compile--known-dynamic-vars
|
||||
(byte-compile--load-dynvars (getenv "EMACS_DYNVARS_FILE")))
|
||||
target-file input-buffer output-buffer
|
||||
byte-compile-dest-file byte-compiler-error-flag)
|
||||
(setq target-file (byte-compile-dest-file filename))
|
||||
(setq byte-compile-dest-file target-file)
|
||||
(with-current-buffer
|
||||
;; It would be cleaner to use a temp buffer, but if there was
|
||||
;; an error, we leave this buffer around for diagnostics.
|
||||
;; Its name is documented in the lispref.
|
||||
(setq input-buffer (get-buffer-create
|
||||
(concat " *Compiler Input*"
|
||||
(if (zerop byte-compile-level) ""
|
||||
(format "-%s" byte-compile-level)))))
|
||||
(erase-buffer)
|
||||
(setq buffer-file-coding-system nil)
|
||||
;; Always compile an Emacs Lisp file as multibyte
|
||||
;; unless the file itself forces unibyte with -*-coding: raw-text;-*-
|
||||
(set-buffer-multibyte t)
|
||||
(insert-file-contents filename)
|
||||
;; Mimic the way after-insert-file-set-coding can make the
|
||||
;; buffer unibyte when visiting this file.
|
||||
(when (or (eq last-coding-system-used 'no-conversion)
|
||||
(eq (coding-system-type last-coding-system-used) 5))
|
||||
;; For coding systems no-conversion and raw-text...,
|
||||
;; edit the buffer as unibyte.
|
||||
(set-buffer-multibyte nil))
|
||||
;; Run hooks including the uncompression hook.
|
||||
;; If they change the file name, then change it for the output also.
|
||||
(let ((buffer-file-name filename)
|
||||
(dmm (default-value 'major-mode))
|
||||
;; Ignore unsafe local variables.
|
||||
;; We only care about a few of them for our purposes.
|
||||
(enable-local-variables :safe)
|
||||
(enable-local-eval nil))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq-default major-mode 'emacs-lisp-mode)
|
||||
;; Arg of t means don't alter enable-local-variables.
|
||||
(delay-mode-hooks (normal-mode t)))
|
||||
(setq-default major-mode dmm))
|
||||
;; There may be a file local variable setting (bug#10419).
|
||||
(setq buffer-read-only nil
|
||||
filename buffer-file-name))
|
||||
;; Don't inherit lexical-binding from caller (bug#12938).
|
||||
(unless (local-variable-p 'lexical-binding)
|
||||
(setq-local lexical-binding nil))
|
||||
;; Set the default directory, in case an eval-when-compile uses it.
|
||||
(setq default-directory (file-name-directory filename)))
|
||||
;; Check if the file's local variables explicitly specify not to
|
||||
;; compile this file.
|
||||
(if (with-current-buffer input-buffer no-byte-compile)
|
||||
(progn
|
||||
;; (message "%s not compiled because of `no-byte-compile: %s'"
|
||||
;; (byte-compile-abbreviate-file filename)
|
||||
;; (with-current-buffer input-buffer no-byte-compile))
|
||||
(when (and target-file (file-exists-p target-file))
|
||||
(message "%s deleted because of `no-byte-compile: %s'"
|
||||
(byte-compile-abbreviate-file target-file)
|
||||
(buffer-local-value 'no-byte-compile input-buffer))
|
||||
(condition-case nil (delete-file target-file) (error nil)))
|
||||
;; We successfully didn't compile this file.
|
||||
'no-byte-compile)
|
||||
(when byte-compile-verbose
|
||||
(message "Compiling %s..." filename))
|
||||
;; It is important that input-buffer not be current at this call,
|
||||
;; so that the value of point set in input-buffer
|
||||
;; within byte-compile-from-buffer lingers in that buffer.
|
||||
(setq output-buffer
|
||||
(save-current-buffer
|
||||
(let ((byte-compile-level (1+ byte-compile-level)))
|
||||
(byte-compile-from-buffer input-buffer))))
|
||||
(if byte-compiler-error-flag
|
||||
nil
|
||||
(when byte-compile-verbose
|
||||
(message "Compiling %s...done" filename))
|
||||
(kill-buffer input-buffer)
|
||||
(with-current-buffer output-buffer
|
||||
(when (and target-file
|
||||
(or (not byte-native-compiling)
|
||||
(and byte-native-compiling byte+native-compile)))
|
||||
(goto-char (point-max))
|
||||
(insert "\n") ; aaah, unix.
|
||||
(cond
|
||||
((and (file-writable-p target-file)
|
||||
;; We attempt to create a temporary file in the
|
||||
;; target directory, so the target directory must be
|
||||
;; writable.
|
||||
(file-writable-p
|
||||
(file-name-directory
|
||||
;; Need to expand in case TARGET-FILE doesn't
|
||||
;; include a directory (Bug#45287).
|
||||
(expand-file-name target-file))))
|
||||
(if byte-native-compiling
|
||||
;; Defer elc production.
|
||||
(setf byte-to-native-output-buffer-file
|
||||
(cons (current-buffer) target-file))
|
||||
(byte-write-target-file (current-buffer) target-file))
|
||||
(or noninteractive
|
||||
byte-native-compiling
|
||||
(message "Wrote %s" target-file)))
|
||||
((file-writable-p target-file)
|
||||
;; In case the target directory isn't writable (see e.g. Bug#44631),
|
||||
;; try writing to the output file directly. We must disable any
|
||||
;; code conversion here.
|
||||
(let ((coding-system-for-write 'no-conversion))
|
||||
(with-file-modes (logand (default-file-modes) #o666)
|
||||
(write-region (point-min) (point-max) target-file nil 1)))
|
||||
(or noninteractive (message "Wrote %s" target-file)))
|
||||
(t
|
||||
;; This is just to give a better error message than write-region
|
||||
(let ((exists (file-exists-p target-file)))
|
||||
(signal (if exists 'file-error 'file-missing)
|
||||
(list "Opening output file"
|
||||
(if exists
|
||||
"Cannot overwrite file"
|
||||
"Directory not writable or nonexistent")
|
||||
target-file))))))
|
||||
(unless byte-native-compiling
|
||||
(kill-buffer (current-buffer))))
|
||||
(if (and byte-compile-generate-call-tree
|
||||
(or (eq t byte-compile-generate-call-tree)
|
||||
(y-or-n-p (format "Report call tree for %s? "
|
||||
filename))))
|
||||
(save-excursion
|
||||
(display-call-tree filename)))
|
||||
(let ((gen-dynvars (getenv "EMACS_GENERATE_DYNVARS")))
|
||||
(when (and gen-dynvars (not (equal gen-dynvars ""))
|
||||
byte-compile--seen-defvars)
|
||||
(let ((dynvar-file (concat target-file ".dynvars")))
|
||||
(message "Generating %s" dynvar-file)
|
||||
(with-temp-buffer
|
||||
(dolist (var (delete-dups byte-compile--seen-defvars))
|
||||
(insert (format "%S\n" (cons var filename))))
|
||||
(write-region (point-min) (point-max) dynvar-file)))))
|
||||
(if load
|
||||
(load target-file))
|
||||
t))))
|
||||
|
||||
;;; compiling a single function
|
||||
;;;###autoload
|
||||
|
@ -4213,11 +4213,13 @@ variable 'NATIVE_DISABLED' is set, only byte compile."
|
||||
(batch-byte-compile)
|
||||
(cl-assert (length= command-line-args-left 1))
|
||||
(let ((byte+native-compile t)
|
||||
(byte-to-native-output-file nil))
|
||||
(byte-to-native-output-buffer-file nil))
|
||||
(batch-native-compile)
|
||||
(pcase byte-to-native-output-file
|
||||
(`(,tempfile . ,target-file)
|
||||
(rename-file tempfile target-file t)))
|
||||
(pcase byte-to-native-output-buffer-file
|
||||
(`(,temp-buffer . ,target-file)
|
||||
(unwind-protect
|
||||
(byte-write-target-file temp-buffer target-file))
|
||||
(kill-buffer temp-buffer)))
|
||||
(setq command-line-args-left (cdr command-line-args-left)))))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -98,7 +98,11 @@ This applies to `eval-defun', `eval-region', `eval-buffer', and
|
||||
You can use the command `edebug-all-defs' to toggle the value of this
|
||||
variable. You may wish to make it local to each buffer with
|
||||
\(make-local-variable \\='edebug-all-defs) in your
|
||||
`emacs-lisp-mode-hook'."
|
||||
`emacs-lisp-mode-hook'.
|
||||
|
||||
Note that this user option has no effect unless the edebug
|
||||
package has been loaded."
|
||||
:require 'edebug
|
||||
:type 'boolean)
|
||||
|
||||
;;;###autoload
|
||||
|
@ -1423,7 +1423,8 @@ Returns the stats object."
|
||||
(message "%9s %S%s"
|
||||
(ert-string-for-test-result result nil)
|
||||
(ert-test-name test)
|
||||
(if (getenv "EMACS_TEST_VERBOSE")
|
||||
(if (cl-plusp
|
||||
(length (getenv "EMACS_TEST_VERBOSE")))
|
||||
(ert-reason-for-test-result result)
|
||||
""))))
|
||||
(message "%s" ""))
|
||||
@ -1435,7 +1436,8 @@ Returns the stats object."
|
||||
(message "%9s %S%s"
|
||||
(ert-string-for-test-result result nil)
|
||||
(ert-test-name test)
|
||||
(if (getenv "EMACS_TEST_VERBOSE")
|
||||
(if (cl-plusp
|
||||
(length (getenv "EMACS_TEST_VERBOSE")))
|
||||
(ert-reason-for-test-result result)
|
||||
""))))
|
||||
(message "%s" ""))
|
||||
|
@ -434,10 +434,16 @@ storage method to list."
|
||||
multisession-edit-mode)
|
||||
(unless id
|
||||
(error "No value on the current line"))
|
||||
(let* ((object (make-multisession
|
||||
:package (car id)
|
||||
:key (cdr id)
|
||||
:storage multisession-storage))
|
||||
(let* ((object (or
|
||||
;; If the multisession variable already exists, use
|
||||
;; it (so that we update it).
|
||||
(and (boundp (intern-soft (cdr id)))
|
||||
(symbol-value (intern (cdr id))))
|
||||
;; Create a new object.
|
||||
(make-multisession
|
||||
:package (car id)
|
||||
:key (cdr id)
|
||||
:storage multisession-storage)))
|
||||
(value (multisession-value object)))
|
||||
(setf (multisession-value object)
|
||||
(car (read-from-string
|
||||
|
@ -273,7 +273,10 @@ Use the `pp-max-width' variable to control the desired line length."
|
||||
(insert "(")
|
||||
(pp--insert start (pop sexp))
|
||||
(while sexp
|
||||
(pp--insert " " (pop sexp)))
|
||||
(if (consp sexp)
|
||||
(pp--insert " " (pop sexp))
|
||||
(pp--insert " . " sexp)
|
||||
(setq sexp nil)))
|
||||
(insert ")")))
|
||||
|
||||
(defun pp--format-function (sexp)
|
||||
|
467
lisp/emacs-lisp/range.el
Normal file
467
lisp/emacs-lisp/range.el
Normal file
@ -0,0 +1,467 @@
|
||||
;;; ranges.el --- range functions -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 1996-2022 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; A "range" is a list that represents a list of integers. A range is
|
||||
;; a list containing cons cells of start/end pairs, as well as integers.
|
||||
;;
|
||||
;; ((2 . 5) 9 (11 . 13))
|
||||
;;
|
||||
;; represents the list (2 3 4 5 9 11 12 13).
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defun range-normalize (range)
|
||||
"Normalize RANGE.
|
||||
If RANGE is a single range, return (RANGE). Otherwise, return RANGE."
|
||||
(if (listp (cdr-safe range))
|
||||
range
|
||||
(list range)))
|
||||
|
||||
(defun range-denormalize (range)
|
||||
"If RANGE contains a single range, then return that.
|
||||
If not, return RANGE as is."
|
||||
(if (and (consp (car range))
|
||||
(length= range 1))
|
||||
(car range)
|
||||
range))
|
||||
|
||||
(defun range-difference (range1 range2)
|
||||
"Return the range of elements in RANGE1 that do not appear in RANGE2.
|
||||
Both ranges must be in ascending order."
|
||||
(setq range1 (range-normalize range1))
|
||||
(setq range2 (range-normalize range2))
|
||||
(let* ((new-range (cons nil (copy-sequence range1)))
|
||||
(r new-range))
|
||||
(while (cdr r)
|
||||
(let* ((r1 (cadr r))
|
||||
(r2 (car range2))
|
||||
(min1 (if (numberp r1) r1 (car r1)))
|
||||
(max1 (if (numberp r1) r1 (cdr r1)))
|
||||
(min2 (if (numberp r2) r2 (car r2)))
|
||||
(max2 (if (numberp r2) r2 (cdr r2))))
|
||||
|
||||
(cond ((> min1 max1)
|
||||
;; Invalid range: may result from overlap condition (below)
|
||||
;; remove Invalid range
|
||||
(setcdr r (cddr r)))
|
||||
((and (= min1 max1)
|
||||
(listp r1))
|
||||
;; Inefficient representation: may result from overlap
|
||||
;; condition (below)
|
||||
(setcar (cdr r) min1))
|
||||
((not min2)
|
||||
;; All done with range2
|
||||
(setq r nil))
|
||||
((< max1 min2)
|
||||
;; No overlap: range1 precedes range2
|
||||
(pop r))
|
||||
((< max2 min1)
|
||||
;; No overlap: range2 precedes range1
|
||||
(pop range2))
|
||||
((and (<= min2 min1) (<= max1 max2))
|
||||
;; Complete overlap: range1 removed
|
||||
(setcdr r (cddr r)))
|
||||
(t
|
||||
(setcdr r (nconc (list (cons min1 (1- min2))
|
||||
(cons (1+ max2) max1))
|
||||
(cddr r)))))))
|
||||
(cdr new-range)))
|
||||
|
||||
(defun range-intersection (range1 range2)
|
||||
"Return intersection of RANGE1 and RANGE2."
|
||||
(let* (out
|
||||
(min1 (car range1))
|
||||
(max1 (if (numberp min1)
|
||||
(if (numberp (cdr range1))
|
||||
(prog1 (cdr range1)
|
||||
(setq range1 nil)) min1)
|
||||
(prog1 (cdr min1)
|
||||
(setq min1 (car min1)))))
|
||||
(min2 (car range2))
|
||||
(max2 (if (numberp min2)
|
||||
(if (numberp (cdr range2))
|
||||
(prog1 (cdr range2)
|
||||
(setq range2 nil)) min2)
|
||||
(prog1 (cdr min2)
|
||||
(setq min2 (car min2))))))
|
||||
(setq range1 (cdr range1)
|
||||
range2 (cdr range2))
|
||||
(while (and min1 min2)
|
||||
(cond ((< max1 min2) ; range1 precedes range2
|
||||
(setq range1 (cdr range1)
|
||||
min1 nil))
|
||||
((< max2 min1) ; range2 precedes range1
|
||||
(setq range2 (cdr range2)
|
||||
min2 nil))
|
||||
(t ; some sort of overlap is occurring
|
||||
(let ((min (max min1 min2))
|
||||
(max (min max1 max2)))
|
||||
(setq out (if (= min max)
|
||||
(cons min out)
|
||||
(cons (cons min max) out))))
|
||||
(if (< max1 max2) ; range1 ends before range2
|
||||
(setq min1 nil) ; incr range1
|
||||
(setq min2 nil)))) ; incr range2
|
||||
(unless min1
|
||||
(setq min1 (car range1)
|
||||
max1 (if (numberp min1) min1
|
||||
(prog1 (cdr min1) (setq min1 (car min1))))
|
||||
range1 (cdr range1)))
|
||||
(unless min2
|
||||
(setq min2 (car range2)
|
||||
max2 (if (numberp min2) min2
|
||||
(prog1 (cdr min2) (setq min2 (car min2))))
|
||||
range2 (cdr range2))))
|
||||
(cond ((cdr out)
|
||||
(nreverse out))
|
||||
((numberp (car out))
|
||||
out)
|
||||
(t
|
||||
(car out)))))
|
||||
|
||||
(defun range-compress-list (numbers)
|
||||
"Convert a sorted list of numbers to a range list."
|
||||
(let ((first (car numbers))
|
||||
(last (car numbers))
|
||||
result)
|
||||
(cond
|
||||
((null numbers)
|
||||
nil)
|
||||
((not (listp (cdr numbers)))
|
||||
numbers)
|
||||
(t
|
||||
(while numbers
|
||||
(cond ((= last (car numbers)) nil) ;Omit duplicated number
|
||||
((= (1+ last) (car numbers)) ;Still in sequence
|
||||
(setq last (car numbers)))
|
||||
(t ;End of one sequence
|
||||
(setq result
|
||||
(cons (if (= first last) first
|
||||
(cons first last))
|
||||
result))
|
||||
(setq first (car numbers))
|
||||
(setq last (car numbers))))
|
||||
(setq numbers (cdr numbers)))
|
||||
(nreverse (cons (if (= first last) first (cons first last))
|
||||
result))))))
|
||||
|
||||
(defun range-uncompress (ranges)
|
||||
"Expand a list of ranges into a list of numbers.
|
||||
RANGES is either a single range on the form `(num . num)' or a list of
|
||||
these ranges."
|
||||
(let (first last result)
|
||||
(cond
|
||||
((null ranges)
|
||||
nil)
|
||||
((not (listp (cdr ranges)))
|
||||
(setq first (car ranges))
|
||||
(setq last (cdr ranges))
|
||||
(while (<= first last)
|
||||
(setq result (cons first result))
|
||||
(setq first (1+ first)))
|
||||
(nreverse result))
|
||||
(t
|
||||
(while ranges
|
||||
(if (atom (car ranges))
|
||||
(when (numberp (car ranges))
|
||||
(setq result (cons (car ranges) result)))
|
||||
(setq first (caar ranges))
|
||||
(setq last (cdar ranges))
|
||||
(while (<= first last)
|
||||
(setq result (cons first result))
|
||||
(setq first (1+ first))))
|
||||
(setq ranges (cdr ranges)))
|
||||
(nreverse result)))))
|
||||
|
||||
(defun range-add-list (ranges list)
|
||||
"Return a list of ranges that has all articles from both RANGES and LIST.
|
||||
Note: LIST has to be sorted over `<'."
|
||||
(if (not ranges)
|
||||
(range-compress-list list)
|
||||
(setq list (copy-sequence list))
|
||||
(unless (listp (cdr ranges))
|
||||
(setq ranges (list ranges)))
|
||||
(let ((out ranges)
|
||||
ilist lowest highest temp)
|
||||
(while (and ranges list)
|
||||
(setq ilist list)
|
||||
(setq lowest (or (and (atom (car ranges)) (car ranges))
|
||||
(caar ranges)))
|
||||
(while (and list (cdr list) (< (cadr list) lowest))
|
||||
(setq list (cdr list)))
|
||||
(when (< (car ilist) lowest)
|
||||
(setq temp list)
|
||||
(setq list (cdr list))
|
||||
(setcdr temp nil)
|
||||
(setq out (nconc (range-compress-list ilist) out)))
|
||||
(setq highest (or (and (atom (car ranges)) (car ranges))
|
||||
(cdar ranges)))
|
||||
(while (and list (<= (car list) highest))
|
||||
(setq list (cdr list)))
|
||||
(setq ranges (cdr ranges)))
|
||||
(when list
|
||||
(setq out (nconc (range-compress-list list) out)))
|
||||
(setq out (sort out (lambda (r1 r2)
|
||||
(< (or (and (atom r1) r1) (car r1))
|
||||
(or (and (atom r2) r2) (car r2))))))
|
||||
(setq ranges out)
|
||||
(while ranges
|
||||
(if (atom (car ranges))
|
||||
(when (cdr ranges)
|
||||
(if (atom (cadr ranges))
|
||||
(when (= (1+ (car ranges)) (cadr ranges))
|
||||
(setcar ranges (cons (car ranges)
|
||||
(cadr ranges)))
|
||||
(setcdr ranges (cddr ranges)))
|
||||
(when (= (1+ (car ranges)) (caadr ranges))
|
||||
(setcar (cadr ranges) (car ranges))
|
||||
(setcar ranges (cadr ranges))
|
||||
(setcdr ranges (cddr ranges)))))
|
||||
(when (cdr ranges)
|
||||
(if (atom (cadr ranges))
|
||||
(when (= (1+ (cdar ranges)) (cadr ranges))
|
||||
(setcdr (car ranges) (cadr ranges))
|
||||
(setcdr ranges (cddr ranges)))
|
||||
(when (= (1+ (cdar ranges)) (caadr ranges))
|
||||
(setcdr (car ranges) (cdadr ranges))
|
||||
(setcdr ranges (cddr ranges))))))
|
||||
(setq ranges (cdr ranges)))
|
||||
out)))
|
||||
|
||||
(defun range-remove (range1 range2)
|
||||
"Return a range that has all articles from RANGE2 removed from RANGE1.
|
||||
The returned range is always a list. RANGE2 can also be a unsorted
|
||||
list of articles. RANGE1 is modified by side effects, RANGE2 is not
|
||||
modified."
|
||||
(if (or (null range1) (null range2))
|
||||
range1
|
||||
(let (out r1 r2 r1-min r1-max r2-min r2-max
|
||||
(range2 (copy-tree range2)))
|
||||
(setq range1 (if (listp (cdr range1)) range1 (list range1))
|
||||
range2 (sort (if (listp (cdr range2)) range2 (list range2))
|
||||
(lambda (e1 e2)
|
||||
(< (if (consp e1) (car e1) e1)
|
||||
(if (consp e2) (car e2) e2))))
|
||||
r1 (car range1)
|
||||
r2 (car range2)
|
||||
r1-min (if (consp r1) (car r1) r1)
|
||||
r1-max (if (consp r1) (cdr r1) r1)
|
||||
r2-min (if (consp r2) (car r2) r2)
|
||||
r2-max (if (consp r2) (cdr r2) r2))
|
||||
(while (and range1 range2)
|
||||
(cond ((< r2-max r1-min) ; r2 < r1
|
||||
(pop range2)
|
||||
(setq r2 (car range2)
|
||||
r2-min (if (consp r2) (car r2) r2)
|
||||
r2-max (if (consp r2) (cdr r2) r2)))
|
||||
((and (<= r2-min r1-min) (<= r1-max r2-max)) ; r2 overlap r1
|
||||
(pop range1)
|
||||
(setq r1 (car range1)
|
||||
r1-min (if (consp r1) (car r1) r1)
|
||||
r1-max (if (consp r1) (cdr r1) r1)))
|
||||
((and (<= r2-min r1-min) (<= r2-max r1-max)) ; r2 overlap min r1
|
||||
(pop range2)
|
||||
(setq r1-min (1+ r2-max)
|
||||
r2 (car range2)
|
||||
r2-min (if (consp r2) (car r2) r2)
|
||||
r2-max (if (consp r2) (cdr r2) r2)))
|
||||
((and (<= r1-min r2-min) (<= r2-max r1-max)) ; r2 contained in r1
|
||||
(if (eq r1-min (1- r2-min))
|
||||
(push r1-min out)
|
||||
(push (cons r1-min (1- r2-min)) out))
|
||||
(pop range2)
|
||||
(if (< r2-max r1-max) ; finished with r1?
|
||||
(setq r1-min (1+ r2-max))
|
||||
(pop range1)
|
||||
(setq r1 (car range1)
|
||||
r1-min (if (consp r1) (car r1) r1)
|
||||
r1-max (if (consp r1) (cdr r1) r1)))
|
||||
(setq r2 (car range2)
|
||||
r2-min (if (consp r2) (car r2) r2)
|
||||
r2-max (if (consp r2) (cdr r2) r2)))
|
||||
((and (<= r2-min r1-max) (<= r1-max r2-max)) ; r2 overlap max r1
|
||||
(if (eq r1-min (1- r2-min))
|
||||
(push r1-min out)
|
||||
(push (cons r1-min (1- r2-min)) out))
|
||||
(pop range1)
|
||||
(setq r1 (car range1)
|
||||
r1-min (if (consp r1) (car r1) r1)
|
||||
r1-max (if (consp r1) (cdr r1) r1)))
|
||||
((< r1-max r2-min) ; r2 > r1
|
||||
(pop range1)
|
||||
(if (eq r1-min r1-max)
|
||||
(push r1-min out)
|
||||
(push (cons r1-min r1-max) out))
|
||||
(setq r1 (car range1)
|
||||
r1-min (if (consp r1) (car r1) r1)
|
||||
r1-max (if (consp r1) (cdr r1) r1)))))
|
||||
(when r1
|
||||
(if (eq r1-min r1-max)
|
||||
(push r1-min out)
|
||||
(push (cons r1-min r1-max) out))
|
||||
(pop range1))
|
||||
(while range1
|
||||
(push (pop range1) out))
|
||||
(nreverse out))))
|
||||
|
||||
(defun range-member-p (number ranges)
|
||||
"Say whether NUMBER is in RANGES."
|
||||
(if (not (listp (cdr ranges)))
|
||||
(and (>= number (car ranges))
|
||||
(<= number (cdr ranges)))
|
||||
(let ((not-stop t))
|
||||
(while (and ranges
|
||||
(if (numberp (car ranges))
|
||||
(>= number (car ranges))
|
||||
(>= number (caar ranges)))
|
||||
not-stop)
|
||||
(when (if (numberp (car ranges))
|
||||
(= number (car ranges))
|
||||
(and (>= number (caar ranges))
|
||||
(<= number (cdar ranges))))
|
||||
(setq not-stop nil))
|
||||
(setq ranges (cdr ranges)))
|
||||
(not not-stop))))
|
||||
|
||||
(defun range-list-intersection (list ranges)
|
||||
"Return a list of numbers in LIST that are members of RANGES.
|
||||
oLIST is a sorted list."
|
||||
(setq ranges (range-normalize ranges))
|
||||
(let (number result)
|
||||
(while (setq number (pop list))
|
||||
(while (and ranges
|
||||
(if (numberp (car ranges))
|
||||
(< (car ranges) number)
|
||||
(< (cdar ranges) number)))
|
||||
(setq ranges (cdr ranges)))
|
||||
(when (and ranges
|
||||
(if (numberp (car ranges))
|
||||
(= (car ranges) number)
|
||||
;; (caar ranges) <= number <= (cdar ranges)
|
||||
(>= number (caar ranges))))
|
||||
(push number result)))
|
||||
(nreverse result)))
|
||||
|
||||
(defun range-list-difference (list ranges)
|
||||
"Return a list of numbers in LIST that are not members of RANGES.
|
||||
LIST is a sorted list."
|
||||
(setq ranges (range-normalize ranges))
|
||||
(let (number result)
|
||||
(while (setq number (pop list))
|
||||
(while (and ranges
|
||||
(if (numberp (car ranges))
|
||||
(< (car ranges) number)
|
||||
(< (cdar ranges) number)))
|
||||
(setq ranges (cdr ranges)))
|
||||
(when (or (not ranges)
|
||||
(if (numberp (car ranges))
|
||||
(not (= (car ranges) number))
|
||||
;; not ((caar ranges) <= number <= (cdar ranges))
|
||||
(< number (caar ranges))))
|
||||
(push number result)))
|
||||
(nreverse result)))
|
||||
|
||||
(defun range-length (range)
|
||||
"Return the length RANGE would have if uncompressed."
|
||||
(cond
|
||||
((null range)
|
||||
0)
|
||||
((not (listp (cdr range)))
|
||||
(- (cdr range) (car range) -1))
|
||||
(t
|
||||
(let ((sum 0))
|
||||
(dolist (x range sum)
|
||||
(setq sum
|
||||
(+ sum (if (consp x) (- (cdr x) (car x) -1) 1))))))))
|
||||
|
||||
(defun range-concat (range1 range2)
|
||||
"Add RANGE2 to RANGE1 (nondestructively)."
|
||||
(unless (listp (cdr range1))
|
||||
(setq range1 (list range1)))
|
||||
(unless (listp (cdr range2))
|
||||
(setq range2 (list range2)))
|
||||
(let ((item1 (pop range1))
|
||||
(item2 (pop range2))
|
||||
range item selector)
|
||||
(while (or item1 item2)
|
||||
(setq selector
|
||||
(cond
|
||||
((null item1) nil)
|
||||
((null item2) t)
|
||||
((and (numberp item1) (numberp item2)) (< item1 item2))
|
||||
((numberp item1) (< item1 (car item2)))
|
||||
((numberp item2) (< (car item1) item2))
|
||||
(t (< (car item1) (car item2)))))
|
||||
(setq item
|
||||
(or
|
||||
(let ((tmp1 item) (tmp2 (if selector item1 item2)))
|
||||
(cond
|
||||
((null tmp1) tmp2)
|
||||
((null tmp2) tmp1)
|
||||
((and (numberp tmp1) (numberp tmp2))
|
||||
(cond
|
||||
((eq tmp1 tmp2) tmp1)
|
||||
((eq (1+ tmp1) tmp2) (cons tmp1 tmp2))
|
||||
((eq (1+ tmp2) tmp1) (cons tmp2 tmp1))
|
||||
(t nil)))
|
||||
((numberp tmp1)
|
||||
(cond
|
||||
((and (>= tmp1 (car tmp2)) (<= tmp1 (cdr tmp2))) tmp2)
|
||||
((eq (1+ tmp1) (car tmp2)) (cons tmp1 (cdr tmp2)))
|
||||
((eq (1- tmp1) (cdr tmp2)) (cons (car tmp2) tmp1))
|
||||
(t nil)))
|
||||
((numberp tmp2)
|
||||
(cond
|
||||
((and (>= tmp2 (car tmp1)) (<= tmp2 (cdr tmp1))) tmp1)
|
||||
((eq (1+ tmp2) (car tmp1)) (cons tmp2 (cdr tmp1)))
|
||||
((eq (1- tmp2) (cdr tmp1)) (cons (car tmp1) tmp2))
|
||||
(t nil)))
|
||||
((< (1+ (cdr tmp1)) (car tmp2)) nil)
|
||||
((< (1+ (cdr tmp2)) (car tmp1)) nil)
|
||||
(t (cons (min (car tmp1) (car tmp2))
|
||||
(max (cdr tmp1) (cdr tmp2))))))
|
||||
(progn
|
||||
(if item (push item range))
|
||||
(if selector item1 item2))))
|
||||
(if selector
|
||||
(setq item1 (pop range1))
|
||||
(setq item2 (pop range2))))
|
||||
(if item (push item range))
|
||||
(reverse range)))
|
||||
|
||||
(defun range-map (func range)
|
||||
"Apply FUNC to each value contained by RANGE."
|
||||
(setq range (range-normalize range))
|
||||
(while range
|
||||
(let ((span (pop range)))
|
||||
(if (numberp span)
|
||||
(funcall func span)
|
||||
(let ((first (car span))
|
||||
(last (cdr span)))
|
||||
(while (<= first last)
|
||||
(funcall func first)
|
||||
(setq first (1+ first))))))))
|
||||
|
||||
(provide 'range)
|
||||
|
||||
;;; range.el ends here
|
@ -731,6 +731,7 @@ Interactively, N is the prefix numeric argument, and defaults to
|
||||
1."
|
||||
(interactive "p")
|
||||
(let ((start (current-column))
|
||||
(entry (tabulated-list-get-entry))
|
||||
(nb-cols (length tabulated-list-format))
|
||||
(col-nb 0)
|
||||
(total-width 0)
|
||||
@ -741,9 +742,14 @@ Interactively, N is the prefix numeric argument, and defaults to
|
||||
(if (> start
|
||||
(setq total-width
|
||||
(+ total-width
|
||||
(setq col-width
|
||||
(cadr (aref tabulated-list-format
|
||||
col-nb))))))
|
||||
(max (setq col-width
|
||||
(cadr (aref tabulated-list-format
|
||||
col-nb)))
|
||||
(string-width (aref entry col-nb)))
|
||||
(or (plist-get (nthcdr 3 (aref tabulated-list-format
|
||||
col-nb))
|
||||
:pad-right)
|
||||
1))))
|
||||
(setq col-nb (1+ col-nb))
|
||||
(setq found t)
|
||||
(setf (cadr (aref tabulated-list-format col-nb))
|
||||
|
@ -82,7 +82,11 @@ equivalent of `echo' can always be achieved by using `identity'."
|
||||
It returns a formatted value that should be passed to `eshell-print'
|
||||
or `eshell-printn' for display."
|
||||
(if eshell-plain-echo-behavior
|
||||
(concat (apply 'eshell-flatten-and-stringify args) "\n")
|
||||
(progn
|
||||
;; If the output does not end in a newline, do not emit one.
|
||||
(setq eshell-ensure-newline-p nil)
|
||||
(concat (apply #'eshell-flatten-and-stringify args)
|
||||
(when output-newline "\n")))
|
||||
(let ((value
|
||||
(cond
|
||||
((= (length args) 0) "")
|
||||
@ -109,18 +113,33 @@ or `eshell-printn' for display."
|
||||
"Implementation of `echo'. See `eshell-plain-echo-behavior'."
|
||||
(eshell-eval-using-options
|
||||
"echo" args
|
||||
'((?n nil nil output-newline "terminate with a newline")
|
||||
(?h "help" nil nil "output this help screen")
|
||||
'((?n nil (nil) output-newline
|
||||
"do not output the trailing newline")
|
||||
(?N nil (t) output-newline
|
||||
"terminate with a newline")
|
||||
(?E nil nil _disable-escapes
|
||||
"don't interpret backslash escapes (default)")
|
||||
(?h "help" nil nil
|
||||
"output this help screen")
|
||||
:preserve-args
|
||||
:usage "[-n] [object]")
|
||||
(eshell-echo args output-newline)))
|
||||
:usage "[OPTION]... [OBJECT]...")
|
||||
(if eshell-plain-echo-behavior
|
||||
(eshell-echo args (if output-newline (car output-newline) t))
|
||||
;; In Emacs 28.1 and earlier, "-n" was used to add a newline to
|
||||
;; non-plain echo in Eshell. This caused confusion due to "-n"
|
||||
;; generally having the opposite meaning for echo. Retain this
|
||||
;; compatibility for the time being. For more info, see
|
||||
;; bug#27361.
|
||||
(when (equal output-newline '(nil))
|
||||
(display-warning
|
||||
:warning "To terminate with a newline, you should use -N instead."))
|
||||
(eshell-echo args output-newline))))
|
||||
|
||||
(defun eshell/printnl (&rest args)
|
||||
"Print out each of the arguments, separated by newlines."
|
||||
"Print out each of the arguments as strings, separated by newlines."
|
||||
(let ((elems (flatten-tree args)))
|
||||
(while elems
|
||||
(eshell-printn (eshell-echo (list (car elems))))
|
||||
(setq elems (cdr elems)))))
|
||||
(dolist (elem elems)
|
||||
(eshell-printn (eshell-stringify elem)))))
|
||||
|
||||
(defun eshell/listify (&rest args)
|
||||
"Return the argument(s) as a single list."
|
||||
|
@ -113,27 +113,13 @@ Comments begin with `#'."
|
||||
|
||||
(defun eshell/source (&rest args)
|
||||
"Source a file in a subshell environment."
|
||||
(eshell-eval-using-options
|
||||
"source" args
|
||||
'((?h "help" nil nil "show this usage screen")
|
||||
:show-usage
|
||||
:usage "FILE [ARGS]
|
||||
Invoke the Eshell commands in FILE in a subshell, binding ARGS to $1,
|
||||
$2, etc.")
|
||||
(eshell-source-file (car args) (cdr args) t)))
|
||||
(eshell-source-file (car args) (cdr args) t))
|
||||
|
||||
(put 'eshell/source 'eshell-no-numeric-conversions t)
|
||||
|
||||
(defun eshell/. (&rest args)
|
||||
"Source a file in the current environment."
|
||||
(eshell-eval-using-options
|
||||
"." args
|
||||
'((?h "help" nil nil "show this usage screen")
|
||||
:show-usage
|
||||
:usage "FILE [ARGS]
|
||||
Invoke the Eshell commands in FILE within the current shell
|
||||
environment, binding ARGS to $1, $2, etc.")
|
||||
(eshell-source-file (car args) (cdr args))))
|
||||
(eshell-source-file (car args) (cdr args)))
|
||||
|
||||
(put 'eshell/. 'eshell-no-numeric-conversions t)
|
||||
|
||||
|
@ -107,6 +107,7 @@
|
||||
(require 'esh-module)
|
||||
(require 'esh-io)
|
||||
(require 'esh-ext)
|
||||
(require 'generator)
|
||||
|
||||
(eval-when-compile
|
||||
(require 'cl-lib)
|
||||
@ -903,21 +904,55 @@ at the moment are:
|
||||
"Completion for the `debug' command."
|
||||
(while (pcomplete-here '("errors" "commands"))))
|
||||
|
||||
(iter-defun eshell--find-subcommands (haystack)
|
||||
"Recursively search for subcommand forms in HAYSTACK.
|
||||
This yields the SUBCOMMANDs when found in forms like
|
||||
\"(eshell-as-subcommand SUBCOMMAND)\"."
|
||||
(dolist (elem haystack)
|
||||
(cond
|
||||
((eq (car-safe elem) 'eshell-as-subcommand)
|
||||
(iter-yield (cdr elem)))
|
||||
((listp elem)
|
||||
(iter-yield-from (eshell--find-subcommands elem))))))
|
||||
|
||||
(defun eshell--invoke-command-directly (command)
|
||||
"Determine whether the given COMMAND can be invoked directly.
|
||||
COMMAND should be a non-top-level Eshell command in parsed form.
|
||||
|
||||
A command can be invoked directly if all of the following are true:
|
||||
|
||||
* The command is of the form
|
||||
\"(eshell-trap-errors (eshell-named-command NAME ARGS))\",
|
||||
where ARGS is optional.
|
||||
|
||||
* NAME is a string referring to an alias function and isn't a
|
||||
complex command (see `eshell-complex-commands').
|
||||
|
||||
* Any subcommands in ARGS can also be invoked directly."
|
||||
(when (and (eq (car command) 'eshell-trap-errors)
|
||||
(eq (car (cadr command)) 'eshell-named-command))
|
||||
(let ((name (cadr (cadr command)))
|
||||
(args (cdr-safe (nth 2 (cadr command)))))
|
||||
(and name (stringp name)
|
||||
(not (member name eshell-complex-commands))
|
||||
(catch 'simple
|
||||
(dolist (pred eshell-complex-commands t)
|
||||
(when (and (functionp pred)
|
||||
(funcall pred name))
|
||||
(throw 'simple nil))))
|
||||
(eshell-find-alias-function name)
|
||||
(catch 'indirect-subcommand
|
||||
(iter-do (subcommand (eshell--find-subcommands args))
|
||||
(unless (eshell--invoke-command-directly subcommand)
|
||||
(throw 'indirect-subcommand nil)))
|
||||
t)))))
|
||||
|
||||
(defun eshell-invoke-directly (command)
|
||||
(let ((base (cadr (nth 2 (nth 2 (cadr command))))) name)
|
||||
(if (and (eq (car base) 'eshell-trap-errors)
|
||||
(eq (car (cadr base)) 'eshell-named-command))
|
||||
(setq name (cadr (cadr base))))
|
||||
(and name (stringp name)
|
||||
(not (member name eshell-complex-commands))
|
||||
(catch 'simple
|
||||
(progn
|
||||
(dolist (pred eshell-complex-commands)
|
||||
(if (and (functionp pred)
|
||||
(funcall pred name))
|
||||
(throw 'simple nil)))
|
||||
t))
|
||||
(eshell-find-alias-function name))))
|
||||
"Determine whether the given COMMAND can be invoked directly.
|
||||
COMMAND should be a top-level Eshell command in parsed form, as
|
||||
produced by `eshell-parse-command'."
|
||||
(let ((base (cadr (nth 2 (nth 2 (cadr command))))))
|
||||
(eshell--invoke-command-directly base)))
|
||||
|
||||
(defun eshell-eval-command (command &optional input)
|
||||
"Evaluate the given COMMAND iteratively."
|
||||
|
@ -257,12 +257,12 @@ triggered to say that the switch is unrecognized."
|
||||
remaining
|
||||
(let ((extcmd (memq ':external options)))
|
||||
(when extcmd
|
||||
(setq extcmd (eshell-search-path (cadr extcmd)))
|
||||
(if extcmd
|
||||
(throw 'eshell-ext-command extcmd)
|
||||
(error (if (characterp (car switch)) "%s: unrecognized option -%c"
|
||||
"%s: unrecognized option --%s")
|
||||
name (car switch))))))))
|
||||
(setq extcmd (eshell-search-path (cadr extcmd))))
|
||||
(if extcmd
|
||||
(throw 'eshell-ext-command extcmd)
|
||||
(error (if (characterp (car switch)) "%s: unrecognized option -%c"
|
||||
"%s: unrecognized option --%s")
|
||||
name (car switch)))))))
|
||||
|
||||
(defun eshell--process-args (name args options)
|
||||
"Process the given ARGS using OPTIONS."
|
||||
|
@ -70,6 +70,13 @@
|
||||
:foreground :background :stipple :overline :strike-through :box
|
||||
:font :inherit :fontset :distant-foreground :extend :vector])
|
||||
|
||||
(defun face-attrs--make-indirect-safe ()
|
||||
"Deep-copy the buffer's `face-remapping-alist' upon cloning the buffer."
|
||||
(setq-local face-remapping-alist
|
||||
(mapcar #'copy-sequence face-remapping-alist)))
|
||||
|
||||
(add-hook 'clone-indirect-buffer-hook #'face-attrs--make-indirect-safe)
|
||||
|
||||
(defun face-attrs-more-relative-p (attrs1 attrs2)
|
||||
"Return true if ATTRS1 contains a greater number of relative
|
||||
face-attributes than ATTRS2. A face attribute is considered
|
||||
|
@ -1107,6 +1107,16 @@ returned. Otherwise, DEFAULT is returned verbatim."
|
||||
(let ((prompt (if default
|
||||
(format-prompt prompt default)
|
||||
(format "%s: " prompt)))
|
||||
(completion-extra-properties
|
||||
'(:affixation-function
|
||||
(lambda (faces)
|
||||
(mapcar
|
||||
(lambda (face)
|
||||
(list (concat (propertize "SAMPLE" 'face face)
|
||||
"\t")
|
||||
""
|
||||
face))
|
||||
faces))))
|
||||
aliasfaces nonaliasfaces faces)
|
||||
;; Build up the completion tables.
|
||||
(mapatoms (lambda (s)
|
||||
|
@ -3968,12 +3968,12 @@ major-mode."
|
||||
;; Discard the prefix.
|
||||
(if (looking-at prefix)
|
||||
(delete-region (point) (match-end 0))
|
||||
(error "Local variables entry is missing the prefix"))
|
||||
(user-error "Local variables entry is missing the prefix"))
|
||||
(end-of-line)
|
||||
;; Discard the suffix.
|
||||
(if (looking-back suffix (line-beginning-position))
|
||||
(delete-region (match-beginning 0) (point))
|
||||
(error "Local variables entry is missing the suffix"))
|
||||
(user-error "Local variables entry is missing the suffix"))
|
||||
(forward-line 1))
|
||||
(goto-char (point-min))
|
||||
|
||||
@ -3981,9 +3981,9 @@ major-mode."
|
||||
(and (eq handle-mode t) result)))
|
||||
;; Find the variable name;
|
||||
(unless (looking-at hack-local-variable-regexp)
|
||||
(error "Malformed local variable line: %S"
|
||||
(buffer-substring-no-properties
|
||||
(point) (line-end-position))))
|
||||
(user-error "Malformed local variable line: %S"
|
||||
(buffer-substring-no-properties
|
||||
(point) (line-end-position))))
|
||||
(goto-char (match-end 1))
|
||||
(let* ((str (match-string 1))
|
||||
(var (intern str))
|
||||
|
@ -31,6 +31,7 @@
|
||||
(require 'gnus-srvr)
|
||||
(require 'gnus-util)
|
||||
(require 'timer)
|
||||
(require 'range)
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
|
||||
(autoload 'gnus-server-update-server "gnus-srvr")
|
||||
@ -1219,8 +1220,8 @@ This can be added to `gnus-select-article-hook' or
|
||||
(cond ((eq mark 'read)
|
||||
(setf (gnus-info-read info)
|
||||
(funcall (if (eq what 'add)
|
||||
#'gnus-range-add
|
||||
#'gnus-remove-from-range)
|
||||
#'range-concat
|
||||
#'range-remove)
|
||||
(gnus-info-read info)
|
||||
range))
|
||||
(gnus-get-unread-articles-in-group
|
||||
@ -1233,8 +1234,8 @@ This can be added to `gnus-select-article-hook' or
|
||||
(gnus-info-marks info)))
|
||||
(setcdr info-marks
|
||||
(funcall (if (eq what 'add)
|
||||
#'gnus-range-add
|
||||
#'gnus-remove-from-range)
|
||||
#'range-concat
|
||||
#'range-remove)
|
||||
(cdr info-marks)
|
||||
range))))))))
|
||||
|
||||
@ -1307,7 +1308,7 @@ downloaded into the agent."
|
||||
|
||||
(let ((read (gnus-info-read info)))
|
||||
(setf (gnus-info-read info)
|
||||
(gnus-range-add
|
||||
(range-concat
|
||||
read
|
||||
(list (cons (1+ agent-max)
|
||||
(1- active-min))))))
|
||||
@ -1796,13 +1797,13 @@ article numbers will be returned."
|
||||
(articles (if fetch-all
|
||||
(if gnus-newsgroup-maximum-articles
|
||||
(let ((active (gnus-active group)))
|
||||
(gnus-uncompress-range
|
||||
(range-uncompress
|
||||
(cons (max (car active)
|
||||
(- (cdr active)
|
||||
gnus-newsgroup-maximum-articles
|
||||
-1))
|
||||
(cdr active))))
|
||||
(gnus-uncompress-range (gnus-active group)))
|
||||
(range-uncompress (gnus-active group)))
|
||||
(gnus-list-of-unread-articles group)))
|
||||
(gnus-decode-encoded-word-function 'identity)
|
||||
(gnus-decode-encoded-address-function 'identity)
|
||||
@ -1817,7 +1818,7 @@ article numbers will be returned."
|
||||
;; because otherwise the agent will remove their marks.)
|
||||
(dolist (arts (gnus-info-marks (gnus-get-info group)))
|
||||
(unless (memq (car arts) '(seen recent killed cache))
|
||||
(setq articles (gnus-range-add articles (cdr arts)))))
|
||||
(setq articles (range-concat articles (cdr arts)))))
|
||||
(setq articles (sort (gnus-uncompress-sequence articles) #'<)))
|
||||
|
||||
;; At this point, I have the list of articles to consider for
|
||||
@ -1851,15 +1852,15 @@ article numbers will be returned."
|
||||
;; gnus-agent-article-alist) equals (cdr (gnus-active
|
||||
;; group))}. The addition of one(the 1+ above) then
|
||||
;; forces Low to be greater than High. When this happens,
|
||||
;; gnus-list-range-intersection returns nil which
|
||||
;; range-list-intersection returns nil which
|
||||
;; indicates that no headers need to be fetched. -- Kevin
|
||||
(setq articles (gnus-list-range-intersection
|
||||
(setq articles (range-list-intersection
|
||||
articles (list (cons low high)))))))
|
||||
|
||||
(when articles
|
||||
(gnus-message
|
||||
10 "gnus-agent-fetch-headers: undownloaded articles are `%s'"
|
||||
(gnus-compress-sequence articles t)))
|
||||
(range-compress-list articles)))
|
||||
|
||||
(with-current-buffer nntp-server-buffer
|
||||
(if articles
|
||||
@ -2060,7 +2061,7 @@ doesn't exist, to valid the overview buffer."
|
||||
(let (state sequence uncomp)
|
||||
(while alist
|
||||
(setq state (caar alist)
|
||||
sequence (inline (gnus-uncompress-range (cdar alist)))
|
||||
sequence (inline (range-uncompress (cdar alist)))
|
||||
alist (cdr alist))
|
||||
(while sequence
|
||||
(push (cons (pop sequence) state) uncomp)))
|
||||
@ -2404,7 +2405,7 @@ contents, they are first saved to their own file."
|
||||
(let ((arts (cdr (assq mark (gnus-info-marks
|
||||
(setq info (gnus-get-info group)))))))
|
||||
(when arts
|
||||
(setq marked-articles (nconc (gnus-uncompress-range arts)
|
||||
(setq marked-articles (nconc (range-uncompress arts)
|
||||
marked-articles))
|
||||
))))
|
||||
(setq marked-articles (sort marked-articles #'<))
|
||||
@ -2544,7 +2545,7 @@ contents, they are first saved to their own file."
|
||||
(let ((read (gnus-info-read
|
||||
(or info (setq info (gnus-get-info group))))))
|
||||
(setf (gnus-info-read info)
|
||||
(gnus-add-to-range read unfetched-articles)))
|
||||
(range-add-list read unfetched-articles)))
|
||||
|
||||
(gnus-group-update-group group t)
|
||||
(sit-for 0)
|
||||
@ -2898,8 +2899,8 @@ The following commands are available:
|
||||
|
||||
(defun gnus-agent-read-p ()
|
||||
"Say whether an article is read or not."
|
||||
(gnus-member-of-range (mail-header-number gnus-headers)
|
||||
(gnus-info-read (gnus-get-info gnus-newsgroup-name))))
|
||||
(range-member-p (mail-header-number gnus-headers)
|
||||
(gnus-info-read (gnus-get-info gnus-newsgroup-name))))
|
||||
|
||||
(defun gnus-category-make-function (predicate)
|
||||
"Make a function from PREDICATE."
|
||||
@ -3115,7 +3116,7 @@ FORCE is equivalent to setting the expiration predicates to true."
|
||||
;; All articles EXCEPT those named by the caller
|
||||
;; are protected from expiration
|
||||
(gnus-sorted-difference
|
||||
(gnus-uncompress-range
|
||||
(range-uncompress
|
||||
(cons (caar alist)
|
||||
(caar (last alist))))
|
||||
(sort articles #'<)))))
|
||||
@ -3137,9 +3138,9 @@ FORCE is equivalent to setting the expiration predicates to true."
|
||||
;; Ticked and/or dormant articles are excluded
|
||||
;; from expiration
|
||||
(nconc
|
||||
(gnus-uncompress-range
|
||||
(range-uncompress
|
||||
(cdr (assq 'tick (gnus-info-marks info))))
|
||||
(gnus-uncompress-range
|
||||
(range-uncompress
|
||||
(cdr (assq 'dormant
|
||||
(gnus-info-marks info))))))))
|
||||
(nov-file (concat dir ".overview"))
|
||||
@ -3638,7 +3639,7 @@ has been fetched."
|
||||
(file-name-directory file) t))
|
||||
|
||||
(when fetch-old
|
||||
(setq articles (gnus-uncompress-range
|
||||
(setq articles (range-uncompress
|
||||
(cons (if (numberp fetch-old)
|
||||
(max 1 (- (car articles) fetch-old))
|
||||
1)
|
||||
@ -3694,7 +3695,7 @@ has been fetched."
|
||||
|
||||
;; Clip this list to the headers that will
|
||||
;; actually be returned
|
||||
(setq fetched-articles (gnus-list-range-intersection
|
||||
(setq fetched-articles (range-list-intersection
|
||||
(cdr fetched-articles)
|
||||
(cons min max)))
|
||||
|
||||
@ -3703,7 +3704,7 @@ has been fetched."
|
||||
;; excluded IDs may be fetchable using HEAD.
|
||||
(if (car tail-fetched-articles)
|
||||
(setq uncached-articles
|
||||
(gnus-list-range-intersection
|
||||
(range-list-intersection
|
||||
uncached-articles
|
||||
(cons (car uncached-articles)
|
||||
(car tail-fetched-articles)))))
|
||||
|
@ -42,6 +42,7 @@
|
||||
(require 'message)
|
||||
(require 'mouse)
|
||||
(require 'seq)
|
||||
(require 'range)
|
||||
|
||||
(autoload 'gnus-msg-mail "gnus-msg" nil t)
|
||||
(autoload 'gnus-button-mailto "gnus-msg")
|
||||
@ -1394,6 +1395,15 @@ predicate. See Info node `(gnus)Customizing Articles'."
|
||||
:link '(custom-manual "(gnus)Customizing Articles")
|
||||
:type gnus-article-treat-custom)
|
||||
|
||||
(defcustom gnus-treat-suspicious-headers 'head
|
||||
"Mark headers that are suspicious.
|
||||
Valid values are nil, t, `head', `first', `last', an integer or a
|
||||
predicate. See Info node `(gnus)Customizing Articles'."
|
||||
:version "29.1"
|
||||
:group 'gnus-article-treat
|
||||
:link '(custom-manual "(gnus)Customizing Articles")
|
||||
:type gnus-article-treat-custom)
|
||||
|
||||
(defcustom gnus-treat-fold-newsgroups 'head
|
||||
"Fold the Newsgroups and Followup-To headers.
|
||||
Valid values are nil, t, `head', `first', `last', an integer or a
|
||||
@ -1711,6 +1721,7 @@ regexp."
|
||||
(gnus-treat-unfold-headers gnus-article-treat-unfold-headers)
|
||||
(gnus-treat-fold-newsgroups gnus-article-treat-fold-newsgroups)
|
||||
(gnus-treat-fold-headers gnus-article-treat-fold-headers)
|
||||
(gnus-treat-suspicious-headers gnus-article-treat-suspicious-headers)
|
||||
(gnus-treat-buttonize-head gnus-article-add-buttons-to-head)
|
||||
(gnus-treat-display-smileys gnus-treat-smiley)
|
||||
(gnus-treat-capitalize-sentences gnus-article-capitalize-sentences)
|
||||
@ -2235,6 +2246,20 @@ unfolded."
|
||||
(pixel-fill-region (point) (point-max) (pixel-fill-width)))
|
||||
(goto-char (point-max))))))
|
||||
|
||||
(defun gnus-article-treat-suspicious-headers ()
|
||||
"Mark suspicious headers."
|
||||
(interactive nil gnus-article-mode gnus-summary-mode)
|
||||
(gnus-with-article-headers
|
||||
(let (match)
|
||||
(while (setq match (text-property-search-forward 'textsec-suspicious))
|
||||
(add-text-properties (prop-match-beginning match)
|
||||
(prop-match-end match)
|
||||
(list 'help-echo (prop-match-value match)
|
||||
'face 'textsec-suspicious))
|
||||
(overlay-put (make-overlay (prop-match-end match)
|
||||
(prop-match-end match))
|
||||
'after-string "⚠️")))))
|
||||
|
||||
(defun gnus-treat-smiley ()
|
||||
"Toggle display of textual emoticons (\"smileys\") as small graphical icons."
|
||||
(interactive nil gnus-article-mode gnus-summary-mode)
|
||||
@ -2611,17 +2636,36 @@ If PROMPT (the prefix), prompt for a coding system to use."
|
||||
(forward-line -1))
|
||||
(setq end (point))
|
||||
(while (not (bobp))
|
||||
(while (progn
|
||||
(forward-line -1)
|
||||
(and (not (bobp))
|
||||
(memq (char-after) '(?\t ? )))))
|
||||
(setq start (point))
|
||||
(if (looking-at "\
|
||||
(let (addresses)
|
||||
(while (progn
|
||||
(forward-line -1)
|
||||
(and (not (bobp))
|
||||
(memq (char-after) '(?\t ? )))))
|
||||
(setq start (point))
|
||||
(save-restriction
|
||||
(narrow-to-region start end)
|
||||
(if (looking-at "\
|
||||
\\(?:Resent-\\)?\\(?:From\\|Cc\\|To\\|Bcc\\|\\(?:In-\\)?Reply-To\\|Sender\
|
||||
\\|Mail-Followup-To\\|Mail-Copies-To\\|Approved\\):")
|
||||
(funcall gnus-decode-address-function start end)
|
||||
(funcall gnus-decode-header-function start end))
|
||||
(goto-char (setq end start)))))
|
||||
(progn
|
||||
(setq addresses (buffer-string))
|
||||
(funcall gnus-decode-address-function (point-min) (point-max)))
|
||||
(funcall gnus-decode-header-function (point-min) (point-max))))
|
||||
(when addresses
|
||||
(article--check-suspicious-addresses addresses))
|
||||
(goto-char (point-max))
|
||||
(goto-char (setq end start))))))
|
||||
|
||||
(defun article--check-suspicious-addresses (addresses)
|
||||
(setq addresses (replace-regexp-in-string "\\`[^:]+:[ \t\n]*" "" addresses))
|
||||
(dolist (header (mail-header-parse-addresses addresses t))
|
||||
(when-let* ((address (car (ignore-errors
|
||||
(mail-header-parse-address header))))
|
||||
(warning (textsec-suspicious-p address 'email-address)))
|
||||
(goto-char (point-min))
|
||||
(while (search-forward address nil t)
|
||||
(put-text-property (match-beginning 0) (match-end 0)
|
||||
'textsec-suspicious warning)))))
|
||||
|
||||
(defun article-decode-group-name ()
|
||||
"Decode group names in Newsgroups, Followup-To and Xref headers."
|
||||
@ -7019,7 +7063,7 @@ then we display only bindings that start with that prefix."
|
||||
(setq sumkeys
|
||||
(append (mapcar
|
||||
#'vector
|
||||
(nreverse (gnus-uncompress-range def)))
|
||||
(nreverse (range-uncompress def)))
|
||||
sumkeys))))
|
||||
((setq def (key-binding key))
|
||||
(unless (eq def 'undefined)
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
(require 'parse-time)
|
||||
(require 'nnimap)
|
||||
(require 'range)
|
||||
|
||||
(eval-when-compile (require 'epg)) ;; setf-method for `epg-context-armor'
|
||||
(autoload 'epg-make-context "epg")
|
||||
@ -404,7 +405,7 @@ When FULL is t, upload everything, not just a difference from the last full."
|
||||
(let* ((group (gnus-group-full-name gnus-cloud-group-name gnus-cloud-method))
|
||||
(active (gnus-active group))
|
||||
headers head)
|
||||
(when (gnus-retrieve-headers (gnus-uncompress-range active) group)
|
||||
(when (gnus-retrieve-headers (range-uncompress active) group)
|
||||
(with-current-buffer nntp-server-buffer
|
||||
(goto-char (point-min))
|
||||
(while (setq head (nnheader-parse-head))
|
||||
|
@ -200,7 +200,7 @@ Obeys the standard process/prefix convention."
|
||||
(gnus-activate-group "nndraft:queue")
|
||||
(save-excursion
|
||||
(let* ((articles (nndraft-articles))
|
||||
(unsendable (gnus-uncompress-range
|
||||
(unsendable (range-uncompress
|
||||
(cdr (assq 'unsend
|
||||
(gnus-info-marks
|
||||
(gnus-get-info "nndraft:queue"))))))
|
||||
|
@ -35,6 +35,7 @@
|
||||
(require 'gnus-undo)
|
||||
(require 'gmm-utils)
|
||||
(require 'time-date)
|
||||
(require 'range)
|
||||
|
||||
(eval-when-compile
|
||||
(require 'mm-url)
|
||||
@ -512,8 +513,8 @@ simple manner."
|
||||
((numberp number)
|
||||
(int-to-string
|
||||
(+ number
|
||||
(gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
|
||||
(gnus-range-length (cdr (assq 'tick gnus-tmp-marked))))))
|
||||
(range-length (cdr (assq 'dormant gnus-tmp-marked)))
|
||||
(range-length (cdr (assq 'tick gnus-tmp-marked))))))
|
||||
(t number))
|
||||
?s)
|
||||
(?R gnus-tmp-number-of-read ?s)
|
||||
@ -523,10 +524,10 @@ simple manner."
|
||||
?s)
|
||||
(?t gnus-tmp-number-total ?d)
|
||||
(?y gnus-tmp-number-of-unread ?s)
|
||||
(?I (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked))) ?d)
|
||||
(?T (gnus-range-length (cdr (assq 'tick gnus-tmp-marked))) ?d)
|
||||
(?i (+ (gnus-range-length (cdr (assq 'dormant gnus-tmp-marked)))
|
||||
(gnus-range-length (cdr (assq 'tick gnus-tmp-marked))))
|
||||
(?I (range-length (cdr (assq 'dormant gnus-tmp-marked))) ?d)
|
||||
(?T (range-length (cdr (assq 'tick gnus-tmp-marked))) ?d)
|
||||
(?i (+ (range-length (cdr (assq 'dormant gnus-tmp-marked)))
|
||||
(range-length (cdr (assq 'tick gnus-tmp-marked))))
|
||||
?d)
|
||||
(?g gnus-tmp-group ?s)
|
||||
(?G gnus-tmp-qualified-group ?s)
|
||||
@ -1482,9 +1483,9 @@ if it is a string, only list groups matching REGEXP."
|
||||
(active (gnus-active group)))
|
||||
(if (not active)
|
||||
0
|
||||
(length (gnus-uncompress-range
|
||||
(gnus-range-difference
|
||||
(gnus-range-difference (list active) (gnus-info-read info))
|
||||
(length (range-uncompress
|
||||
(range-difference
|
||||
(range-difference (list active) (gnus-info-read info))
|
||||
seen))))))
|
||||
|
||||
;; Moving through the Group buffer (in topic mode) e.g. with C-n doesn't
|
||||
@ -1642,7 +1643,7 @@ Some value are bound so the form can use them."
|
||||
'(mail post-mail))))
|
||||
(cons 'level (or (gnus-info-level info) gnus-level-killed))
|
||||
(cons 'score (or (gnus-info-score info) 0))
|
||||
(cons 'ticked (gnus-range-length (cdr (assq 'tick marked))))
|
||||
(cons 'ticked (range-length (cdr (assq 'tick marked))))
|
||||
(cons 'group-age (gnus-group-timestamp-delta group)))))
|
||||
(while (and list
|
||||
(not (eval (caar list) env)))
|
||||
@ -2065,9 +2066,9 @@ that group."
|
||||
(- (1+ (cdr active)) (car active)))))
|
||||
(gnus-summary-read-group
|
||||
group (or all (and (numberp number)
|
||||
(zerop (+ number (gnus-range-length
|
||||
(zerop (+ number (range-length
|
||||
(cdr (assq 'tick marked)))
|
||||
(gnus-range-length
|
||||
(range-length
|
||||
(cdr (assq 'dormant marked)))))))
|
||||
no-article nil no-display nil select-articles)))
|
||||
|
||||
@ -2832,7 +2833,7 @@ according to the expiry settings. Note that this will delete old
|
||||
not-expirable articles, too."
|
||||
(interactive (list (gnus-group-group-name) current-prefix-arg)
|
||||
gnus-group-mode)
|
||||
(let ((articles (gnus-uncompress-range (gnus-active group))))
|
||||
(let ((articles (range-uncompress (gnus-active group))))
|
||||
(when (gnus-yes-or-no-p
|
||||
(format "Do you really want to delete these %d articles forever? "
|
||||
(length articles)))
|
||||
@ -3755,15 +3756,15 @@ or nil if no action could be taken."
|
||||
'del '(tick))
|
||||
(list (cdr (assq 'dormant marks))
|
||||
'del '(dormant))))
|
||||
(setq unread (gnus-range-add (gnus-range-add
|
||||
unread (cdr (assq 'dormant marks)))
|
||||
(cdr (assq 'tick marks))))
|
||||
(setq unread (range-concat (range-concat
|
||||
unread (cdr (assq 'dormant marks)))
|
||||
(cdr (assq 'tick marks))))
|
||||
(gnus-add-marked-articles group 'tick nil nil 'force)
|
||||
(gnus-add-marked-articles group 'dormant nil nil 'force))
|
||||
;; Do auto-expirable marks if that's required.
|
||||
(when (and (gnus-group-auto-expirable-p group)
|
||||
(not (gnus-group-read-only-p group)))
|
||||
(gnus-range-map
|
||||
(range-map
|
||||
(lambda (article)
|
||||
(gnus-add-marked-articles group 'expire (list article))
|
||||
(gnus-request-set-mark group (list (list (list article)
|
||||
@ -3795,7 +3796,7 @@ Uses the process/prefix convention."
|
||||
(cons nil (gnus-list-of-read-articles group))
|
||||
(assq 'expire (gnus-info-marks info))))
|
||||
(articles-to-expire
|
||||
(gnus-list-range-difference
|
||||
(range-list-difference
|
||||
(gnus-uncompress-sequence (cdr expirable))
|
||||
(cdr (assq 'unexist (gnus-info-marks info)))))
|
||||
(expiry-wait (gnus-group-find-parameter group 'expiry-wait))
|
||||
@ -4671,23 +4672,22 @@ and the second element is the address."
|
||||
(and (not (setq marked (nthcdr 3 info)))
|
||||
(or (null articles)
|
||||
(setcdr (nthcdr 2 info)
|
||||
(list (list (cons type (gnus-compress-sequence
|
||||
articles t)))))))
|
||||
(list (list (cons type (range-compress-list
|
||||
articles)))))))
|
||||
(and (not (setq m (assq type (car marked))))
|
||||
(or (null articles)
|
||||
(setcar marked
|
||||
(cons (cons type (gnus-compress-sequence articles t) )
|
||||
(cons (cons type (range-compress-list articles))
|
||||
(car marked)))))
|
||||
(if force
|
||||
(if (null articles)
|
||||
(setcar (nthcdr 3 info)
|
||||
(assq-delete-all type (car marked)))
|
||||
(setcdr m (gnus-compress-sequence articles t)))
|
||||
(setcdr m (gnus-compress-sequence
|
||||
(sort (nconc (gnus-uncompress-range (cdr m))
|
||||
(setcdr m (range-compress-list articles)))
|
||||
(setcdr m (range-compress-list
|
||||
(sort (nconc (range-uncompress (cdr m))
|
||||
(copy-sequence articles))
|
||||
#'<)
|
||||
t))))))
|
||||
#'<)))))))
|
||||
|
||||
(declare-function gnus-summary-add-mark "gnus-sum" (article type))
|
||||
|
||||
|
@ -802,7 +802,7 @@ If GROUP is nil, all groups on COMMAND-METHOD are scanned."
|
||||
(when (> min 1)
|
||||
(let* ((range (if (= min 2) 1 (cons 1 (1- min))))
|
||||
(read (gnus-info-read info))
|
||||
(new-read (gnus-range-add read (list range))))
|
||||
(new-read (range-concat read (list range))))
|
||||
(setf (gnus-info-read info) new-read)))
|
||||
info))))))
|
||||
|
||||
|
@ -349,7 +349,7 @@ Returns the number of articles marked as read."
|
||||
(setq gnus-newsgroup-kill-headers
|
||||
(mapcar #'mail-header-number headers))
|
||||
(while headers
|
||||
(unless (gnus-member-of-range
|
||||
(unless (range-member-p
|
||||
(mail-header-number (car headers))
|
||||
gnus-newsgroup-killed)
|
||||
(push (mail-header-number (car headers))
|
||||
|
@ -26,10 +26,8 @@
|
||||
|
||||
;;; List and range functions
|
||||
|
||||
(defsubst gnus-range-normalize (range)
|
||||
"Normalize RANGE.
|
||||
If RANGE is a single range, return (RANGE). Otherwise, return RANGE."
|
||||
(if (listp (cdr-safe range)) range (list range)))
|
||||
(require 'range)
|
||||
(define-obsolete-function-alias 'gnus-range-normalize #'range-normalize "29.1")
|
||||
|
||||
(defun gnus-last-element (list)
|
||||
"Return last element of LIST."
|
||||
@ -56,10 +54,10 @@ If RANGE is a single range, return (RANGE). Otherwise, return RANGE."
|
||||
"Return a range comprising all the RANGES, which are pre-sorted.
|
||||
RANGES will be destructively altered."
|
||||
(setq ranges (delete nil ranges))
|
||||
(let* ((result (gnus-range-normalize (pop ranges)))
|
||||
(let* ((result (range-normalize (pop ranges)))
|
||||
(last (last result)))
|
||||
(dolist (range ranges)
|
||||
(setq range (gnus-range-normalize range))
|
||||
(setq range (range-normalize range))
|
||||
;; Normalize the single-number case, so that we don't need to
|
||||
;; special-case that so much.
|
||||
(when (numberp (car last))
|
||||
@ -82,47 +80,8 @@ RANGES will be destructively altered."
|
||||
(car result)
|
||||
result)))
|
||||
|
||||
(defun gnus-range-difference (range1 range2)
|
||||
"Return the range of elements in RANGE1 that do not appear in RANGE2.
|
||||
Both ranges must be in ascending order."
|
||||
(setq range1 (gnus-range-normalize range1))
|
||||
(setq range2 (gnus-range-normalize range2))
|
||||
(let* ((new-range (cons nil (copy-sequence range1)))
|
||||
(r new-range)
|
||||
) ;; (safe t)
|
||||
(while (cdr r)
|
||||
(let* ((r1 (cadr r))
|
||||
(r2 (car range2))
|
||||
(min1 (if (numberp r1) r1 (car r1)))
|
||||
(max1 (if (numberp r1) r1 (cdr r1)))
|
||||
(min2 (if (numberp r2) r2 (car r2)))
|
||||
(max2 (if (numberp r2) r2 (cdr r2))))
|
||||
|
||||
(cond ((> min1 max1)
|
||||
;; Invalid range: may result from overlap condition (below)
|
||||
;; remove Invalid range
|
||||
(setcdr r (cddr r)))
|
||||
((and (= min1 max1)
|
||||
(listp r1))
|
||||
;; Inefficient representation: may result from overlap condition (below)
|
||||
(setcar (cdr r) min1))
|
||||
((not min2)
|
||||
;; All done with range2
|
||||
(setq r nil))
|
||||
((< max1 min2)
|
||||
;; No overlap: range1 precedes range2
|
||||
(pop r))
|
||||
((< max2 min1)
|
||||
;; No overlap: range2 precedes range1
|
||||
(pop range2))
|
||||
((and (<= min2 min1) (<= max1 max2))
|
||||
;; Complete overlap: range1 removed
|
||||
(setcdr r (cddr r)))
|
||||
(t
|
||||
(setcdr r (nconc (list (cons min1 (1- min2)) (cons (1+ max2) max1)) (cddr r)))))))
|
||||
(cdr new-range)))
|
||||
|
||||
|
||||
(define-obsolete-function-alias 'gnus-range-difference
|
||||
#'range-difference "29.1")
|
||||
|
||||
;;;###autoload
|
||||
(defun gnus-sorted-difference (list1 list2)
|
||||
@ -200,57 +159,8 @@ LIST1 and LIST2 have to be sorted over <."
|
||||
(setq list2 (cdr list2)))))
|
||||
(nreverse out)))
|
||||
|
||||
;;;###autoload
|
||||
(defun gnus-sorted-range-intersection (range1 range2)
|
||||
"Return intersection of RANGE1 and RANGE2.
|
||||
RANGE1 and RANGE2 have to be sorted over <."
|
||||
(let* (out
|
||||
(min1 (car range1))
|
||||
(max1 (if (numberp min1)
|
||||
(if (numberp (cdr range1))
|
||||
(prog1 (cdr range1)
|
||||
(setq range1 nil)) min1)
|
||||
(prog1 (cdr min1)
|
||||
(setq min1 (car min1)))))
|
||||
(min2 (car range2))
|
||||
(max2 (if (numberp min2)
|
||||
(if (numberp (cdr range2))
|
||||
(prog1 (cdr range2)
|
||||
(setq range2 nil)) min2)
|
||||
(prog1 (cdr min2)
|
||||
(setq min2 (car min2))))))
|
||||
(setq range1 (cdr range1)
|
||||
range2 (cdr range2))
|
||||
(while (and min1 min2)
|
||||
(cond ((< max1 min2) ; range1 precedes range2
|
||||
(setq range1 (cdr range1)
|
||||
min1 nil))
|
||||
((< max2 min1) ; range2 precedes range1
|
||||
(setq range2 (cdr range2)
|
||||
min2 nil))
|
||||
(t ; some sort of overlap is occurring
|
||||
(let ((min (max min1 min2))
|
||||
(max (min max1 max2)))
|
||||
(setq out (if (= min max)
|
||||
(cons min out)
|
||||
(cons (cons min max) out))))
|
||||
(if (< max1 max2) ; range1 ends before range2
|
||||
(setq min1 nil) ; incr range1
|
||||
(setq min2 nil)))) ; incr range2
|
||||
(unless min1
|
||||
(setq min1 (car range1)
|
||||
max1 (if (numberp min1) min1 (prog1 (cdr min1) (setq min1 (car min1))))
|
||||
range1 (cdr range1)))
|
||||
(unless min2
|
||||
(setq min2 (car range2)
|
||||
max2 (if (numberp min2) min2 (prog1 (cdr min2) (setq min2 (car min2))))
|
||||
range2 (cdr range2))))
|
||||
(cond ((cdr out)
|
||||
(nreverse out))
|
||||
((numberp (car out))
|
||||
out)
|
||||
(t
|
||||
(car out)))))
|
||||
(define-obsolete-function-alias 'gnus-sorted-range-intersection
|
||||
#'range-intersection "29.1")
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'gnus-set-sorted-intersection 'gnus-sorted-nintersection)
|
||||
@ -327,315 +237,33 @@ LIST1 and LIST2 have to be sorted over <."
|
||||
"Convert sorted list of numbers to a list of ranges or a single range.
|
||||
If ALWAYS-LIST is non-nil, this function will always release a list of
|
||||
ranges."
|
||||
(let* ((first (car numbers))
|
||||
(last (car numbers))
|
||||
result)
|
||||
(if (null numbers)
|
||||
nil
|
||||
(if (not (listp (cdr numbers)))
|
||||
numbers
|
||||
(while numbers
|
||||
(cond ((= last (car numbers)) nil) ;Omit duplicated number
|
||||
((= (1+ last) (car numbers)) ;Still in sequence
|
||||
(setq last (car numbers)))
|
||||
(t ;End of one sequence
|
||||
(setq result
|
||||
(cons (if (= first last) first
|
||||
(cons first last))
|
||||
result))
|
||||
(setq first (car numbers))
|
||||
(setq last (car numbers))))
|
||||
(setq numbers (cdr numbers)))
|
||||
(if (and (not always-list) (null result))
|
||||
(if (= first last) (list first) (cons first last))
|
||||
(nreverse (cons (if (= first last) first (cons first last))
|
||||
result)))))))
|
||||
(if always-list
|
||||
(range-compress-list numbers)
|
||||
(range-denormalize (range-compress-list numbers))))
|
||||
|
||||
(defalias 'gnus-uncompress-sequence 'gnus-uncompress-range)
|
||||
(defun gnus-uncompress-range (ranges)
|
||||
"Expand a list of ranges into a list of numbers.
|
||||
RANGES is either a single range on the form `(num . num)' or a list of
|
||||
these ranges."
|
||||
(let (first last result)
|
||||
(cond
|
||||
((null ranges)
|
||||
nil)
|
||||
((not (listp (cdr ranges)))
|
||||
(setq first (car ranges))
|
||||
(setq last (cdr ranges))
|
||||
(while (<= first last)
|
||||
(setq result (cons first result))
|
||||
(setq first (1+ first)))
|
||||
(nreverse result))
|
||||
(t
|
||||
(while ranges
|
||||
(if (atom (car ranges))
|
||||
(when (numberp (car ranges))
|
||||
(setq result (cons (car ranges) result)))
|
||||
(setq first (caar ranges))
|
||||
(setq last (cdar ranges))
|
||||
(while (<= first last)
|
||||
(setq result (cons first result))
|
||||
(setq first (1+ first))))
|
||||
(setq ranges (cdr ranges)))
|
||||
(nreverse result)))))
|
||||
(define-obsolete-function-alias 'gnus-uncompress-range
|
||||
#'range-uncompress "29.1")
|
||||
|
||||
(defun gnus-add-to-range (ranges list)
|
||||
"Return a list of ranges that has all articles from both RANGES and LIST.
|
||||
Note: LIST has to be sorted over `<'."
|
||||
(if (not ranges)
|
||||
(gnus-compress-sequence list t)
|
||||
(setq list (copy-sequence list))
|
||||
(unless (listp (cdr ranges))
|
||||
(setq ranges (list ranges)))
|
||||
(let ((out ranges)
|
||||
ilist lowest highest temp)
|
||||
(while (and ranges list)
|
||||
(setq ilist list)
|
||||
(setq lowest (or (and (atom (car ranges)) (car ranges))
|
||||
(caar ranges)))
|
||||
(while (and list (cdr list) (< (cadr list) lowest))
|
||||
(setq list (cdr list)))
|
||||
(when (< (car ilist) lowest)
|
||||
(setq temp list)
|
||||
(setq list (cdr list))
|
||||
(setcdr temp nil)
|
||||
(setq out (nconc (gnus-compress-sequence ilist t) out)))
|
||||
(setq highest (or (and (atom (car ranges)) (car ranges))
|
||||
(cdar ranges)))
|
||||
(while (and list (<= (car list) highest))
|
||||
(setq list (cdr list)))
|
||||
(setq ranges (cdr ranges)))
|
||||
(when list
|
||||
(setq out (nconc (gnus-compress-sequence list t) out)))
|
||||
(setq out (sort out (lambda (r1 r2)
|
||||
(< (or (and (atom r1) r1) (car r1))
|
||||
(or (and (atom r2) r2) (car r2))))))
|
||||
(setq ranges out)
|
||||
(while ranges
|
||||
(if (atom (car ranges))
|
||||
(when (cdr ranges)
|
||||
(if (atom (cadr ranges))
|
||||
(when (= (1+ (car ranges)) (cadr ranges))
|
||||
(setcar ranges (cons (car ranges)
|
||||
(cadr ranges)))
|
||||
(setcdr ranges (cddr ranges)))
|
||||
(when (= (1+ (car ranges)) (caadr ranges))
|
||||
(setcar (cadr ranges) (car ranges))
|
||||
(setcar ranges (cadr ranges))
|
||||
(setcdr ranges (cddr ranges)))))
|
||||
(when (cdr ranges)
|
||||
(if (atom (cadr ranges))
|
||||
(when (= (1+ (cdar ranges)) (cadr ranges))
|
||||
(setcdr (car ranges) (cadr ranges))
|
||||
(setcdr ranges (cddr ranges)))
|
||||
(when (= (1+ (cdar ranges)) (caadr ranges))
|
||||
(setcdr (car ranges) (cdadr ranges))
|
||||
(setcdr ranges (cddr ranges))))))
|
||||
(setq ranges (cdr ranges)))
|
||||
out)))
|
||||
(define-obsolete-function-alias 'gnus-add-to-range
|
||||
#'range-add-list "29.1")
|
||||
|
||||
(defun gnus-remove-from-range (range1 range2)
|
||||
"Return a range that has all articles from RANGE2 removed from RANGE1.
|
||||
The returned range is always a list. RANGE2 can also be a unsorted
|
||||
list of articles. RANGE1 is modified by side effects, RANGE2 is not
|
||||
modified."
|
||||
(if (or (null range1) (null range2))
|
||||
range1
|
||||
(let (out r1 r2 r1_min r1_max r2_min r2_max
|
||||
(range2 (copy-tree range2)))
|
||||
(setq range1 (if (listp (cdr range1)) range1 (list range1))
|
||||
range2 (sort (if (listp (cdr range2)) range2 (list range2))
|
||||
(lambda (e1 e2)
|
||||
(< (if (consp e1) (car e1) e1)
|
||||
(if (consp e2) (car e2) e2))))
|
||||
r1 (car range1)
|
||||
r2 (car range2)
|
||||
r1_min (if (consp r1) (car r1) r1)
|
||||
r1_max (if (consp r1) (cdr r1) r1)
|
||||
r2_min (if (consp r2) (car r2) r2)
|
||||
r2_max (if (consp r2) (cdr r2) r2))
|
||||
(while (and range1 range2)
|
||||
(cond ((< r2_max r1_min) ; r2 < r1
|
||||
(pop range2)
|
||||
(setq r2 (car range2)
|
||||
r2_min (if (consp r2) (car r2) r2)
|
||||
r2_max (if (consp r2) (cdr r2) r2)))
|
||||
((and (<= r2_min r1_min) (<= r1_max r2_max)) ; r2 overlap r1
|
||||
(pop range1)
|
||||
(setq r1 (car range1)
|
||||
r1_min (if (consp r1) (car r1) r1)
|
||||
r1_max (if (consp r1) (cdr r1) r1)))
|
||||
((and (<= r2_min r1_min) (<= r2_max r1_max)) ; r2 overlap min r1
|
||||
(pop range2)
|
||||
(setq r1_min (1+ r2_max)
|
||||
r2 (car range2)
|
||||
r2_min (if (consp r2) (car r2) r2)
|
||||
r2_max (if (consp r2) (cdr r2) r2)))
|
||||
((and (<= r1_min r2_min) (<= r2_max r1_max)) ; r2 contained in r1
|
||||
(if (eq r1_min (1- r2_min))
|
||||
(push r1_min out)
|
||||
(push (cons r1_min (1- r2_min)) out))
|
||||
(pop range2)
|
||||
(if (< r2_max r1_max) ; finished with r1?
|
||||
(setq r1_min (1+ r2_max))
|
||||
(pop range1)
|
||||
(setq r1 (car range1)
|
||||
r1_min (if (consp r1) (car r1) r1)
|
||||
r1_max (if (consp r1) (cdr r1) r1)))
|
||||
(setq r2 (car range2)
|
||||
r2_min (if (consp r2) (car r2) r2)
|
||||
r2_max (if (consp r2) (cdr r2) r2)))
|
||||
((and (<= r2_min r1_max) (<= r1_max r2_max)) ; r2 overlap max r1
|
||||
(if (eq r1_min (1- r2_min))
|
||||
(push r1_min out)
|
||||
(push (cons r1_min (1- r2_min)) out))
|
||||
(pop range1)
|
||||
(setq r1 (car range1)
|
||||
r1_min (if (consp r1) (car r1) r1)
|
||||
r1_max (if (consp r1) (cdr r1) r1)))
|
||||
((< r1_max r2_min) ; r2 > r1
|
||||
(pop range1)
|
||||
(if (eq r1_min r1_max)
|
||||
(push r1_min out)
|
||||
(push (cons r1_min r1_max) out))
|
||||
(setq r1 (car range1)
|
||||
r1_min (if (consp r1) (car r1) r1)
|
||||
r1_max (if (consp r1) (cdr r1) r1)))))
|
||||
(when r1
|
||||
(if (eq r1_min r1_max)
|
||||
(push r1_min out)
|
||||
(push (cons r1_min r1_max) out))
|
||||
(pop range1))
|
||||
(while range1
|
||||
(push (pop range1) out))
|
||||
(nreverse out))))
|
||||
(define-obsolete-function-alias 'gnus-remove-from-range
|
||||
#'range-remove "29.1")
|
||||
|
||||
(defun gnus-member-of-range (number ranges)
|
||||
(if (not (listp (cdr ranges)))
|
||||
(and (>= number (car ranges))
|
||||
(<= number (cdr ranges)))
|
||||
(let ((not-stop t))
|
||||
(while (and ranges
|
||||
(if (numberp (car ranges))
|
||||
(>= number (car ranges))
|
||||
(>= number (caar ranges)))
|
||||
not-stop)
|
||||
(when (if (numberp (car ranges))
|
||||
(= number (car ranges))
|
||||
(and (>= number (caar ranges))
|
||||
(<= number (cdar ranges))))
|
||||
(setq not-stop nil))
|
||||
(setq ranges (cdr ranges)))
|
||||
(not not-stop))))
|
||||
(define-obsolete-function-alias 'gnus-member-of-range #'range-member-p "29.1")
|
||||
|
||||
(defun gnus-list-range-intersection (list ranges)
|
||||
"Return a list of numbers in LIST that are members of RANGES.
|
||||
LIST is a sorted list."
|
||||
(setq ranges (gnus-range-normalize ranges))
|
||||
(let (number result)
|
||||
(while (setq number (pop list))
|
||||
(while (and ranges
|
||||
(if (numberp (car ranges))
|
||||
(< (car ranges) number)
|
||||
(< (cdar ranges) number)))
|
||||
(setq ranges (cdr ranges)))
|
||||
(when (and ranges
|
||||
(if (numberp (car ranges))
|
||||
(= (car ranges) number)
|
||||
;; (caar ranges) <= number <= (cdar ranges)
|
||||
(>= number (caar ranges))))
|
||||
(push number result)))
|
||||
(nreverse result)))
|
||||
(define-obsolete-function-alias 'gnus-list-range-intersection
|
||||
#'range-list-intersection "29.1")
|
||||
|
||||
(defalias 'gnus-inverse-list-range-intersection 'gnus-list-range-difference)
|
||||
|
||||
(defun gnus-list-range-difference (list ranges)
|
||||
"Return a list of numbers in LIST that are not members of RANGES.
|
||||
LIST is a sorted list."
|
||||
(setq ranges (gnus-range-normalize ranges))
|
||||
(let (number result)
|
||||
(while (setq number (pop list))
|
||||
(while (and ranges
|
||||
(if (numberp (car ranges))
|
||||
(< (car ranges) number)
|
||||
(< (cdar ranges) number)))
|
||||
(setq ranges (cdr ranges)))
|
||||
(when (or (not ranges)
|
||||
(if (numberp (car ranges))
|
||||
(not (= (car ranges) number))
|
||||
;; not ((caar ranges) <= number <= (cdar ranges))
|
||||
(< number (caar ranges))))
|
||||
(push number result)))
|
||||
(nreverse result)))
|
||||
(define-obsolete-function-alias 'gnus-list-range-difference
|
||||
#'range-list-difference "29.1")
|
||||
|
||||
(defun gnus-range-length (range)
|
||||
"Return the length RANGE would have if uncompressed."
|
||||
(cond
|
||||
((null range)
|
||||
0)
|
||||
((not (listp (cdr range)))
|
||||
(- (cdr range) (car range) -1))
|
||||
(t
|
||||
(let ((sum 0))
|
||||
(dolist (x range sum)
|
||||
(setq sum
|
||||
(+ sum (if (consp x) (- (cdr x) (car x) -1) 1))))))))
|
||||
(define-obsolete-function-alias 'gnus-range-length #'range-length "29.1")
|
||||
|
||||
(defun gnus-range-add (range1 range2)
|
||||
"Add RANGE2 to RANGE1 (nondestructively)."
|
||||
(unless (listp (cdr range1))
|
||||
(setq range1 (list range1)))
|
||||
(unless (listp (cdr range2))
|
||||
(setq range2 (list range2)))
|
||||
(let ((item1 (pop range1))
|
||||
(item2 (pop range2))
|
||||
range item selector)
|
||||
(while (or item1 item2)
|
||||
(setq selector
|
||||
(cond
|
||||
((null item1) nil)
|
||||
((null item2) t)
|
||||
((and (numberp item1) (numberp item2)) (< item1 item2))
|
||||
((numberp item1) (< item1 (car item2)))
|
||||
((numberp item2) (< (car item1) item2))
|
||||
(t (< (car item1) (car item2)))))
|
||||
(setq item
|
||||
(or
|
||||
(let ((tmp1 item) (tmp2 (if selector item1 item2)))
|
||||
(cond
|
||||
((null tmp1) tmp2)
|
||||
((null tmp2) tmp1)
|
||||
((and (numberp tmp1) (numberp tmp2))
|
||||
(cond
|
||||
((eq tmp1 tmp2) tmp1)
|
||||
((eq (1+ tmp1) tmp2) (cons tmp1 tmp2))
|
||||
((eq (1+ tmp2) tmp1) (cons tmp2 tmp1))
|
||||
(t nil)))
|
||||
((numberp tmp1)
|
||||
(cond
|
||||
((and (>= tmp1 (car tmp2)) (<= tmp1 (cdr tmp2))) tmp2)
|
||||
((eq (1+ tmp1) (car tmp2)) (cons tmp1 (cdr tmp2)))
|
||||
((eq (1- tmp1) (cdr tmp2)) (cons (car tmp2) tmp1))
|
||||
(t nil)))
|
||||
((numberp tmp2)
|
||||
(cond
|
||||
((and (>= tmp2 (car tmp1)) (<= tmp2 (cdr tmp1))) tmp1)
|
||||
((eq (1+ tmp2) (car tmp1)) (cons tmp2 (cdr tmp1)))
|
||||
((eq (1- tmp2) (cdr tmp1)) (cons (car tmp1) tmp2))
|
||||
(t nil)))
|
||||
((< (1+ (cdr tmp1)) (car tmp2)) nil)
|
||||
((< (1+ (cdr tmp2)) (car tmp1)) nil)
|
||||
(t (cons (min (car tmp1) (car tmp2))
|
||||
(max (cdr tmp1) (cdr tmp2))))))
|
||||
(progn
|
||||
(if item (push item range))
|
||||
(if selector item1 item2))))
|
||||
(if selector
|
||||
(setq item1 (pop range1))
|
||||
(setq item2 (pop range2))))
|
||||
(if item (push item range))
|
||||
(reverse range)))
|
||||
(define-obsolete-function-alias 'gnus-range-add #'range-concat "29.1")
|
||||
|
||||
;;;###autoload
|
||||
(defun gnus-add-to-sorted-list (list num)
|
||||
@ -649,18 +277,7 @@ LIST is a sorted list."
|
||||
(setcdr prev (cons num list)))
|
||||
(cdr top)))
|
||||
|
||||
(defun gnus-range-map (func range)
|
||||
"Apply FUNC to each value contained by RANGE."
|
||||
(setq range (gnus-range-normalize range))
|
||||
(while range
|
||||
(let ((span (pop range)))
|
||||
(if (numberp span)
|
||||
(funcall func span)
|
||||
(let ((first (car span))
|
||||
(last (cdr span)))
|
||||
(while (<= first last)
|
||||
(funcall func first)
|
||||
(setq first (1+ first))))))))
|
||||
(define-obsolete-function-alias 'gnus-range-map #'range-map "29.1")
|
||||
|
||||
(provide 'gnus-range)
|
||||
|
||||
|
@ -1884,13 +1884,12 @@ The info element is shared with the same element of
|
||||
(ranges (gnus-info-read info))
|
||||
news article)
|
||||
(while articles
|
||||
(when (gnus-member-of-range
|
||||
(setq article (pop articles)) ranges)
|
||||
(when (range-member-p (setq article (pop articles)) ranges)
|
||||
(push article news)))
|
||||
(when news
|
||||
;; Enter this list into the group info.
|
||||
(setf (gnus-info-read info)
|
||||
(gnus-remove-from-range (gnus-info-read info) (nreverse news)))
|
||||
(range-remove (gnus-info-read info) (nreverse news)))
|
||||
|
||||
;; Set the number of unread articles in gnus-newsrc-hashtb.
|
||||
(gnus-get-unread-articles-in-group info (gnus-active group))
|
||||
@ -2362,10 +2361,10 @@ The form should return either t or nil."
|
||||
ticked (cdr (assq 'tick marks)))
|
||||
(when (or dormant ticked)
|
||||
(setf (gnus-info-read info)
|
||||
(gnus-add-to-range
|
||||
(range-add-list
|
||||
(gnus-info-read info)
|
||||
(nconc (gnus-uncompress-range dormant)
|
||||
(gnus-uncompress-range ticked)))))))))
|
||||
(nconc (range-uncompress dormant)
|
||||
(range-uncompress ticked)))))))))
|
||||
|
||||
(defun gnus-load (file)
|
||||
"Load FILE, but in such a way that read errors can be reported."
|
||||
@ -2457,8 +2456,7 @@ The form should return either t or nil."
|
||||
(unless (nthcdr 3 info)
|
||||
(nconc info (list nil)))
|
||||
(setf (gnus-info-marks info)
|
||||
(list (cons 'tick (gnus-compress-sequence
|
||||
(sort (cdr m) #'<) t))))))
|
||||
(list (cons 'tick (range-compress-list (sort (cdr m) #'<)))))))
|
||||
(setq newsrc killed)
|
||||
(while newsrc
|
||||
(setcar newsrc (caar newsrc))
|
||||
|
@ -5755,7 +5755,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
||||
;; (let ((n (cdr (gnus-active group))))
|
||||
;; (lambda () (> number (- n display))))
|
||||
(setq select-articles
|
||||
(gnus-uncompress-range
|
||||
(range-uncompress
|
||||
(cons (let ((tmp (- (cdr (gnus-active group)) display)))
|
||||
(if (> tmp 0)
|
||||
tmp
|
||||
@ -5928,7 +5928,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
||||
"Find out what articles the user wants to read."
|
||||
(let* ((only-read-p t)
|
||||
(articles
|
||||
(gnus-list-range-difference
|
||||
(range-list-difference
|
||||
;; Select all articles if `read-all' is non-nil, or if there
|
||||
;; are no unread articles.
|
||||
(if (or read-all
|
||||
@ -5943,13 +5943,13 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
||||
(or
|
||||
(if gnus-newsgroup-maximum-articles
|
||||
(let ((active (gnus-active group)))
|
||||
(gnus-uncompress-range
|
||||
(range-uncompress
|
||||
(cons (max (car active)
|
||||
(- (cdr active)
|
||||
gnus-newsgroup-maximum-articles
|
||||
-1))
|
||||
(cdr active))))
|
||||
(gnus-uncompress-range (gnus-active group)))
|
||||
(range-uncompress (gnus-active group)))
|
||||
(gnus-cache-articles-in-group group))
|
||||
;; Select only the "normal" subset of articles.
|
||||
(setq only-read-p nil)
|
||||
@ -6040,7 +6040,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
||||
(defun gnus-killed-articles (killed articles)
|
||||
(let (out)
|
||||
(while articles
|
||||
(when (inline (gnus-member-of-range (car articles) killed))
|
||||
(when (inline (range-member-p (car articles) killed))
|
||||
(push (car articles) out))
|
||||
(setq articles (cdr articles)))
|
||||
out))
|
||||
@ -6078,7 +6078,7 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
||||
;; Adjust "simple" lists - compressed yet unsorted
|
||||
((eq mark-type 'list)
|
||||
;; Simultaneously uncompress and clip to active range
|
||||
;; See gnus-uncompress-range for a description of possible marks
|
||||
;; See range-uncompress for a description of possible marks
|
||||
(let (l lh)
|
||||
(if (not (cadr marks))
|
||||
(set var nil)
|
||||
@ -6177,10 +6177,10 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
||||
;; When exiting the group, everything that's previously been
|
||||
;; unseen is now seen.
|
||||
(when (eq (cdr type) 'seen)
|
||||
(setq list (gnus-range-add list gnus-newsgroup-unseen)))
|
||||
(setq list (range-concat list gnus-newsgroup-unseen)))
|
||||
|
||||
(when (eq (gnus-article-mark-to-type (cdr type)) 'list)
|
||||
(setq list (gnus-compress-sequence (set symbol (sort list #'<)) t)))
|
||||
(setq list (range-compress-list (set symbol (sort list #'<)))))
|
||||
|
||||
(when (and (gnus-check-backend-function
|
||||
'request-set-mark gnus-newsgroup-name)
|
||||
@ -6189,20 +6189,19 @@ If SELECT-ARTICLES, only select those articles from GROUP."
|
||||
;; Don't do anything about marks for articles we
|
||||
;; didn't actually get any headers for.
|
||||
(del
|
||||
(gnus-list-range-intersection
|
||||
(range-list-intersection
|
||||
gnus-newsgroup-articles
|
||||
(gnus-remove-from-range (copy-tree old) list)))
|
||||
(range-remove (copy-tree old) list)))
|
||||
(add
|
||||
(gnus-list-range-intersection
|
||||
(range-list-intersection
|
||||
gnus-newsgroup-articles
|
||||
(gnus-remove-from-range
|
||||
(copy-tree list) old))))
|
||||
(range-remove (copy-tree list) old))))
|
||||
(when add
|
||||
(push (list add 'add (list (cdr type))) delta-marks))
|
||||
(when del
|
||||
;; Don't delete marks from outside the active range.
|
||||
;; This shouldn't happen, but is a sanity check.
|
||||
(setq del (gnus-sorted-range-intersection
|
||||
(setq del (range-intersection
|
||||
(gnus-active gnus-newsgroup-name) del))
|
||||
(push (list del 'del (list (cdr type))) delta-marks))))
|
||||
|
||||
@ -6386,7 +6385,7 @@ The resulting hash table is returned, or nil if no Xrefs were found."
|
||||
(setq ninfo (cons 1 (1- (car active))))
|
||||
(setq ninfo (gnus-info-read info)))
|
||||
;; Then we add the read articles to the range.
|
||||
(gnus-add-to-range
|
||||
(range-add-list
|
||||
ninfo (setq articles (sort articles #'<))))))
|
||||
|
||||
(defun gnus-group-make-articles-read (group articles)
|
||||
@ -6967,10 +6966,10 @@ displayed, no centering will be performed."
|
||||
(marked (gnus-info-marks info))
|
||||
(active (gnus-active group)))
|
||||
(and info active
|
||||
(gnus-list-range-difference
|
||||
(gnus-list-range-difference
|
||||
(range-list-difference
|
||||
(range-list-difference
|
||||
(gnus-sorted-complement
|
||||
(gnus-uncompress-range
|
||||
(range-uncompress
|
||||
(if gnus-newsgroup-maximum-articles
|
||||
(cons (max (car active)
|
||||
(- (cdr active)
|
||||
@ -7129,12 +7128,11 @@ The prefix argument ALL means to select all articles."
|
||||
(when group
|
||||
(when gnus-newsgroup-kill-headers
|
||||
(setq gnus-newsgroup-killed
|
||||
(gnus-compress-sequence
|
||||
(range-compress-list
|
||||
(gnus-sorted-union
|
||||
(gnus-list-range-intersection
|
||||
(range-list-intersection
|
||||
gnus-newsgroup-unselected gnus-newsgroup-killed)
|
||||
gnus-newsgroup-unreads)
|
||||
t)))
|
||||
gnus-newsgroup-unreads))))
|
||||
(unless (listp (cdr gnus-newsgroup-killed))
|
||||
(setq gnus-newsgroup-killed (list gnus-newsgroup-killed)))
|
||||
(let ((headers gnus-newsgroup-headers)
|
||||
@ -10241,8 +10239,8 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
|
||||
(cdr art-group))
|
||||
(push 'read to-marks)
|
||||
(setf (gnus-info-read info)
|
||||
(gnus-add-to-range (gnus-info-read info)
|
||||
(list (cdr art-group)))))
|
||||
(range-add-list (gnus-info-read info)
|
||||
(list (cdr art-group)))))
|
||||
|
||||
;; See whether the article is to be put in the cache.
|
||||
(let* ((expirable (gnus-group-auto-expirable-p to-group))
|
||||
@ -10525,7 +10523,7 @@ This will be the case if the article has both been mailed and posted."
|
||||
;; This backend supports expiry.
|
||||
(let* ((total (gnus-group-total-expirable-p gnus-newsgroup-name))
|
||||
(expirable
|
||||
(gnus-list-range-difference
|
||||
(range-list-difference
|
||||
(if total
|
||||
(progn
|
||||
;; We need to update the info for
|
||||
@ -11898,7 +11896,8 @@ Returns nil if no threads were there to be hidden."
|
||||
(beginning-of-line)
|
||||
(let ((start (point))
|
||||
(starteol (line-end-position))
|
||||
(article (gnus-summary-article-number)))
|
||||
(article (unless (gnus-summary-article-intangible-p)
|
||||
(gnus-summary-article-number))))
|
||||
;; Go forward until either the buffer ends or the subthread ends.
|
||||
(when (and (not (eobp))
|
||||
(or (zerop (gnus-summary-next-thread 1 t))
|
||||
@ -11912,7 +11911,9 @@ Returns nil if no threads were there to be hidden."
|
||||
(let ((ol (make-overlay starteol (point) nil t nil)))
|
||||
(overlay-put ol 'invisible 'gnus-sum)
|
||||
(overlay-put ol 'evaporate t)))
|
||||
(gnus-summary-goto-subject article)
|
||||
(if article
|
||||
(gnus-summary-goto-subject article)
|
||||
(gnus-summary-position-point))
|
||||
;; We moved backward past the start point (invisible thread?)
|
||||
(when (> start (point))
|
||||
(goto-char starteol)))
|
||||
@ -12871,8 +12872,8 @@ UNREAD is a sorted list."
|
||||
(gnus-find-method-for-group group)
|
||||
'server-marks)
|
||||
(gnus-check-backend-function 'request-set-mark group))
|
||||
(let ((del (gnus-remove-from-range (gnus-info-read info) read))
|
||||
(add (gnus-remove-from-range read (gnus-info-read info))))
|
||||
(let ((del (range-remove (gnus-info-read info) read))
|
||||
(add (range-remove read (gnus-info-read info))))
|
||||
(when (or add del)
|
||||
(unless (gnus-check-group group)
|
||||
(error "Can't open server for %s" group))
|
||||
@ -13130,10 +13131,10 @@ If ALL is a number, fetch this number of articles."
|
||||
;; Some nntp servers lie about their active range. When
|
||||
;; this happens, the active range can be in the millions.
|
||||
;; Use a compressed range to avoid creating a huge list.
|
||||
(gnus-range-difference
|
||||
(gnus-range-difference (list gnus-newsgroup-active) old)
|
||||
(range-difference
|
||||
(range-difference (list gnus-newsgroup-active) old)
|
||||
gnus-newsgroup-unexist))
|
||||
(setq len (gnus-range-length older))
|
||||
(setq len (range-length older))
|
||||
(cond
|
||||
((null older) nil)
|
||||
((numberp all)
|
||||
@ -13150,9 +13151,9 @@ If ALL is a number, fetch this number of articles."
|
||||
(push max older)
|
||||
(setq all (1- all)
|
||||
max (1- max))))))
|
||||
(setq older (gnus-uncompress-range older))))
|
||||
(setq older (range-uncompress older))))
|
||||
(all
|
||||
(setq older (gnus-uncompress-range older)))
|
||||
(setq older (range-uncompress older)))
|
||||
(t
|
||||
(when (and (numberp gnus-large-newsgroup)
|
||||
(> len gnus-large-newsgroup))
|
||||
@ -13187,7 +13188,7 @@ If ALL is a number, fetch this number of articles."
|
||||
(push max older)
|
||||
(setq all (1- all)
|
||||
max (1- max))))))))))
|
||||
(setq older (gnus-uncompress-range older))))
|
||||
(setq older (range-uncompress older))))
|
||||
(if (not older)
|
||||
(message "No old news.")
|
||||
(gnus-summary-insert-articles older)
|
||||
|
@ -31,6 +31,7 @@
|
||||
(autoload 'pop3-movemail "pop3")
|
||||
(autoload 'pop3-get-message-count "pop3")
|
||||
(require 'mm-util)
|
||||
(require 'gnus-range)
|
||||
(require 'message) ;; for `message-directory'
|
||||
|
||||
(defvar display-time-mail-function)
|
||||
@ -1048,8 +1049,6 @@ This only works when `display-time' is enabled."
|
||||
(autoload 'imap-range-to-message-set "imap")
|
||||
(autoload 'nnheader-ms-strip-cr "nnheader")
|
||||
|
||||
(autoload 'gnus-compress-sequence "gnus-range")
|
||||
|
||||
(defvar mail-source-imap-file-coding-system 'binary
|
||||
"Coding system for the crashbox made by `mail-source-fetch-imap'.")
|
||||
|
||||
|
@ -4357,7 +4357,11 @@ it is left unchanged."
|
||||
(defun message-update-smtp-method-header ()
|
||||
"Insert an X-Message-SMTP-Method header according to `message-server-alist'."
|
||||
(unless (message-fetch-field "X-Message-SMTP-Method")
|
||||
(let ((from (cadr (mail-extract-address-components (message-fetch-field "From"))))
|
||||
(let ((from (cadr (mail-extract-address-components
|
||||
(save-restriction
|
||||
(widen)
|
||||
(message-narrow-to-headers-or-head)
|
||||
(message-fetch-field "From")))))
|
||||
method)
|
||||
(catch 'exit
|
||||
(dolist (server message-server-alist)
|
||||
@ -4901,7 +4905,18 @@ If you always want Gnus to send messages in one piece, set
|
||||
(message-generate-headers '(Lines)))
|
||||
;; Remove some headers.
|
||||
(message-remove-header message-ignored-mail-headers t)
|
||||
(mail-encode-encoded-word-buffer))
|
||||
(mail-encode-encoded-word-buffer)
|
||||
;; Then check for suspicious addresses.
|
||||
(dolist (hdr '("To" "Cc" "Bcc"))
|
||||
(let ((addr (message-fetch-field hdr)))
|
||||
(when (stringp addr)
|
||||
(dolist (address (mail-header-parse-addresses addr t))
|
||||
(when-let ((warning (textsec-suspicious-p
|
||||
address 'email-address-header)))
|
||||
(unless (y-or-n-p
|
||||
(format "Suspicious address: %s; send anyway?"
|
||||
warning))
|
||||
(user-error "Suspicious address %s" address))))))))
|
||||
(goto-char (point-max))
|
||||
;; require one newline at the end.
|
||||
(or (= (preceding-char) ?\n)
|
||||
|
@ -504,8 +504,6 @@ If MODE is not set, try to find mode automatically."
|
||||
(setq coding-system (mm-find-buffer-file-coding-system)))
|
||||
(setq text (buffer-string))))
|
||||
(with-temp-buffer
|
||||
(buffer-disable-undo)
|
||||
(mm-enable-multibyte)
|
||||
(insert (cond ((eq charset 'gnus-decoded)
|
||||
(with-current-buffer (mm-handle-buffer handle)
|
||||
(buffer-string)))
|
||||
|
@ -27,6 +27,7 @@
|
||||
;;; Code:
|
||||
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
(require 'range)
|
||||
|
||||
(defvar gnus-decode-encoded-word-function)
|
||||
(defvar gnus-decode-encoded-address-function)
|
||||
@ -44,8 +45,6 @@
|
||||
(require 'mm-util)
|
||||
(require 'gnus-util)
|
||||
(autoload 'gnus-remove-odd-characters "gnus-sum")
|
||||
(autoload 'gnus-range-add "gnus-range")
|
||||
(autoload 'gnus-remove-from-range "gnus-range")
|
||||
;; FIXME none of these are used explicitly in this file.
|
||||
(autoload 'gnus-sorted-intersection "gnus-range")
|
||||
(autoload 'gnus-intersection "gnus-range")
|
||||
@ -1044,10 +1043,9 @@ See `find-file-noselect' for the arguments."
|
||||
mark
|
||||
(cond
|
||||
((eq what 'add)
|
||||
(gnus-range-add (cdr (assoc mark backend-marks)) range))
|
||||
(range-concat (cdr (assoc mark backend-marks)) range))
|
||||
((eq what 'del)
|
||||
(gnus-remove-from-range
|
||||
(cdr (assoc mark backend-marks)) range))
|
||||
(range-remove (cdr (assoc mark backend-marks)) range))
|
||||
((eq what 'set)
|
||||
range))
|
||||
backend-marks)))))
|
||||
|
@ -1660,13 +1660,13 @@ If LIMIT, first try to limit the search to the N last articles."
|
||||
(cdr (assoc '%Seen flags))
|
||||
(cdr (assoc '%Deleted flags))))
|
||||
(cdr (assoc '%Flagged flags)))))
|
||||
(read (gnus-range-difference
|
||||
(read (range-difference
|
||||
(cons start-article high) unread)))
|
||||
(when (> start-article 1)
|
||||
(setq read
|
||||
(gnus-range-nconcat
|
||||
(if (> start-article 1)
|
||||
(gnus-sorted-range-intersection
|
||||
(range-intersection
|
||||
(cons 1 (1- start-article))
|
||||
(gnus-info-read info))
|
||||
(gnus-info-read info))
|
||||
@ -1691,7 +1691,7 @@ If LIMIT, first try to limit the search to the N last articles."
|
||||
(pop old-marks)
|
||||
(when (and old-marks
|
||||
(> start-article 1))
|
||||
(setq old-marks (gnus-range-difference
|
||||
(setq old-marks (range-difference
|
||||
old-marks
|
||||
(cons start-article high)))
|
||||
(setq new-marks (gnus-range-nconcat old-marks new-marks)))
|
||||
@ -1702,15 +1702,15 @@ If LIMIT, first try to limit the search to the N last articles."
|
||||
(active (gnus-active group))
|
||||
(unexists
|
||||
(if completep
|
||||
(gnus-range-difference
|
||||
(range-difference
|
||||
active
|
||||
(gnus-compress-sequence existing))
|
||||
(gnus-add-to-range
|
||||
(range-add-list
|
||||
(cdr old-unexists)
|
||||
(gnus-list-range-difference
|
||||
(range-list-difference
|
||||
existing (gnus-active group))))))
|
||||
(when (> (car active) 1)
|
||||
(setq unexists (gnus-range-add
|
||||
(setq unexists (range-concat
|
||||
(cons 1 (1- (car active)))
|
||||
unexists)))
|
||||
(if old-unexists
|
||||
@ -1733,10 +1733,9 @@ If LIMIT, first try to limit the search to the N last articles."
|
||||
(defun nnimap-update-qresync-info (info existing vanished flags)
|
||||
;; Add all the vanished articles to the list of read articles.
|
||||
(setf (gnus-info-read info)
|
||||
(gnus-add-to-range
|
||||
(gnus-add-to-range
|
||||
(gnus-range-add (gnus-info-read info)
|
||||
vanished)
|
||||
(range-add-list
|
||||
(range-add-list
|
||||
(range-concat (gnus-info-read info) vanished)
|
||||
(cdr (assq '%Flagged flags)))
|
||||
(cdr (assq '%Seen flags))))
|
||||
(let ((marks (gnus-info-marks info)))
|
||||
@ -1750,9 +1749,9 @@ If LIMIT, first try to limit the search to the N last articles."
|
||||
(setq marks (delq ticks marks))
|
||||
(pop ticks)
|
||||
;; Add the new marks we got.
|
||||
(setq ticks (gnus-add-to-range ticks new-marks))
|
||||
(setq ticks (range-add-list ticks new-marks))
|
||||
;; Remove the marks from messages that don't have them.
|
||||
(setq ticks (gnus-remove-from-range
|
||||
(setq ticks (range-remove
|
||||
ticks
|
||||
(gnus-compress-sequence
|
||||
(gnus-sorted-complement existing new-marks))))
|
||||
@ -1762,7 +1761,7 @@ If LIMIT, first try to limit the search to the N last articles."
|
||||
;; Add vanished to the list of unexisting articles.
|
||||
(when vanished
|
||||
(let* ((old-unexists (assq 'unexist marks))
|
||||
(unexists (gnus-range-add (cdr old-unexists) vanished)))
|
||||
(unexists (range-concat (cdr old-unexists) vanished)))
|
||||
(if old-unexists
|
||||
(setcdr old-unexists unexists)
|
||||
(push (cons 'unexist unexists) marks)))
|
||||
@ -2242,7 +2241,7 @@ Return the server's response to the SELECT or EXAMINE command."
|
||||
(while (re-search-forward "^\\([0-9]+\\) OK\\b" nil t)
|
||||
(setq sequence (string-to-number (match-string 1)))
|
||||
(when (setq range (cadr (assq sequence sequences)))
|
||||
(push (gnus-uncompress-range range) copied)))
|
||||
(push (range-uncompress range) copied)))
|
||||
(gnus-compress-sequence (sort (apply #'nconc copied) #'<))))
|
||||
|
||||
(defun nnimap-new-articles (flags)
|
||||
|
@ -1006,10 +1006,10 @@ This variable is set by `nnmaildir-request-article'.")
|
||||
existing (nnmaildir--grp-nlist group)
|
||||
existing (mapcar #'car existing)
|
||||
existing (nreverse existing)
|
||||
existing (gnus-compress-sequence existing 'always-list)
|
||||
existing (range-compress-list existing)
|
||||
missing (list (cons 1 (nnmaildir--group-maxnum
|
||||
nnmaildir--cur-server group)))
|
||||
missing (gnus-range-difference missing existing)
|
||||
missing (range-difference missing existing)
|
||||
dir (nnmaildir--srv-dir nnmaildir--cur-server)
|
||||
dir (nnmaildir--srvgrp-dir dir gname)
|
||||
dir (nnmaildir--nndir dir)
|
||||
@ -1076,10 +1076,10 @@ This variable is set by `nnmaildir-request-article'.")
|
||||
(let ((article (nnmaildir--flist-art flist prefix)))
|
||||
(when article
|
||||
(push (nnmaildir--art-num article) article-list))))))
|
||||
(setq ranges (gnus-add-to-range ranges (sort article-list #'<)))))
|
||||
(setq ranges (range-add-list ranges (sort article-list #'<)))))
|
||||
(if (eq mark 'read) (setq read ranges)
|
||||
(if ranges (setq marks (cons (cons mark ranges) marks)))))
|
||||
(setf (gnus-info-read info) (gnus-range-add read missing))
|
||||
(setf (gnus-info-read info) (range-concat read missing))
|
||||
(gnus-info-set-marks info marks 'extend)
|
||||
(setf (nnmaildir--grp-mmth group) new-mmth)
|
||||
info)))
|
||||
@ -1548,11 +1548,11 @@ This variable is set by `nnmaildir-request-article'.")
|
||||
(unless group
|
||||
(setf (nnmaildir--srv-error nnmaildir--cur-server)
|
||||
(if gname (concat "No such group: " gname) "No current group"))
|
||||
(throw 'return (gnus-uncompress-range ranges)))
|
||||
(throw 'return (range-uncompress ranges)))
|
||||
(setq gname (nnmaildir--grp-name group)
|
||||
pgname (nnmaildir--pgname nnmaildir--cur-server gname))
|
||||
(if (nnmaildir--param pgname 'read-only)
|
||||
(throw 'return (gnus-uncompress-range ranges)))
|
||||
(throw 'return (range-uncompress ranges)))
|
||||
(setq time (nnmaildir--param pgname 'expire-age))
|
||||
(unless time
|
||||
(setq time (or (and nnmail-expiry-wait-function
|
||||
@ -1564,7 +1564,7 @@ This variable is set by `nnmaildir-request-article'.")
|
||||
(setq time (round (* time 86400))))))
|
||||
(when no-force
|
||||
(unless (integerp time) ;; handle 'never
|
||||
(throw 'return (gnus-uncompress-range ranges)))
|
||||
(throw 'return (range-uncompress ranges)))
|
||||
(setq boundary (time-since time)))
|
||||
(setq dir (nnmaildir--srv-dir nnmaildir--cur-server)
|
||||
dir (nnmaildir--srvgrp-dir dir gname)
|
||||
@ -1686,7 +1686,7 @@ This variable is set by `nnmaildir-request-article'.")
|
||||
(setf (nnmaildir--srv-error nnmaildir--cur-server)
|
||||
(concat "No such group: " gname))
|
||||
(dolist (action actions)
|
||||
(setq ranges (gnus-range-add ranges (car action))))
|
||||
(setq ranges (range-concat ranges (car action))))
|
||||
(throw 'return ranges))
|
||||
(setq nlist (nnmaildir--grp-nlist group)
|
||||
marksdir (nnmaildir--srv-dir nnmaildir--cur-server)
|
||||
|
@ -597,7 +597,7 @@ Other back ends might or might not work.")
|
||||
(dolist (cur actions)
|
||||
(let ((type (nth 1 cur))
|
||||
(cmdmarks (nth 2 cur))
|
||||
(range (gnus-uncompress-range (nth 0 cur)))
|
||||
(range (range-uncompress (nth 0 cur)))
|
||||
mid ogroup temp) ;; number method
|
||||
(when (and corr
|
||||
(not (zerop (cadr corr))))
|
||||
|
@ -529,7 +529,7 @@
|
||||
;; add article to index, either by building complete list
|
||||
;; in reverse order, or as a list of ranges.
|
||||
(if (not nnmbox-group-building-active-articles)
|
||||
(setcdr entry (gnus-add-to-range (cdr entry) (list article)))
|
||||
(setcdr entry (range-add-list (cdr entry) (list article)))
|
||||
(when (memq article (cdr entry))
|
||||
(switch-to-buffer nnmbox-mbox-buffer)
|
||||
(error "Article %s:%d already exists!" group article))
|
||||
@ -548,10 +548,10 @@
|
||||
nnmbox-group-active-articles)
|
||||
(car nnmbox-group-active-articles)))))
|
||||
;; remove article from index
|
||||
(setcdr entry (gnus-remove-from-range (cdr entry) (list article)))))
|
||||
(setcdr entry (range-remove (cdr entry) (list article)))))
|
||||
|
||||
(defun nnmbox-is-article-active-p (article)
|
||||
(gnus-member-of-range
|
||||
(range-member-p
|
||||
article
|
||||
(cdr (assoc nnmbox-current-group
|
||||
nnmbox-group-active-articles))))
|
||||
|
@ -1078,21 +1078,20 @@ Use the nov database for the current group if available."
|
||||
;; #### doing anything on them.
|
||||
;; 2 a/ read articles:
|
||||
(let ((read (gnus-info-read info)))
|
||||
(setq read (gnus-remove-from-range read (list new-number)))
|
||||
(when (gnus-member-of-range old-number read)
|
||||
(setq read (gnus-remove-from-range read (list old-number)))
|
||||
(setq read (gnus-add-to-range read (list new-number))))
|
||||
(setq read (range-remove read (list new-number)))
|
||||
(when (range-member-p old-number read)
|
||||
(setq read (range-remove read (list old-number)))
|
||||
(setq read (range-add-list read (list new-number))))
|
||||
(setf (gnus-info-read info) read))
|
||||
;; 2 b/ marked articles:
|
||||
(let ((oldmarks (gnus-info-marks info))
|
||||
mark newmarks)
|
||||
(while (setq mark (pop oldmarks))
|
||||
(setcdr mark (gnus-remove-from-range (cdr mark)
|
||||
(list new-number)))
|
||||
(when (gnus-member-of-range old-number (cdr mark))
|
||||
(setcdr mark (gnus-remove-from-range (cdr mark)
|
||||
(list old-number)))
|
||||
(setcdr mark (gnus-add-to-range (cdr mark)
|
||||
(setcdr mark (range-remove (cdr mark) (list new-number)))
|
||||
(when (range-member-p old-number (cdr mark))
|
||||
(setcdr mark (range-remove (cdr mark)
|
||||
(list old-number)))
|
||||
(setcdr mark (range-add-list (cdr mark)
|
||||
(list new-number))))
|
||||
(push mark newmarks))
|
||||
(setf (gnus-info-marks info) newmarks))
|
||||
|
@ -207,7 +207,7 @@ as `(keyfunc member)' and the corresponding element is just
|
||||
(inline-quote
|
||||
(cond
|
||||
((eq ,type 'range)
|
||||
(nnselect-categorize (gnus-uncompress-range ,articles)
|
||||
(nnselect-categorize (range-uncompress ,articles)
|
||||
#'nnselect-article-group #'nnselect-article-number))
|
||||
((eq ,type 'tuple)
|
||||
(nnselect-categorize ,articles
|
||||
@ -542,10 +542,10 @@ If this variable is nil, or if the provided function returns nil,
|
||||
(group-info (gnus-get-info artgroup))
|
||||
(marks (gnus-info-marks group-info))
|
||||
(unread (gnus-uncompress-sequence
|
||||
(gnus-range-difference (gnus-active artgroup)
|
||||
(gnus-info-read group-info)))))
|
||||
(range-difference (gnus-active artgroup)
|
||||
(gnus-info-read group-info)))))
|
||||
(setf (gnus-info-read info)
|
||||
(gnus-add-to-range
|
||||
(range-add-list
|
||||
(gnus-info-read info)
|
||||
(delq nil (mapcar
|
||||
(lambda (art)
|
||||
@ -567,7 +567,7 @@ If this variable is nil, or if the provided function returns nil,
|
||||
artids))
|
||||
(t
|
||||
(setq mark-list
|
||||
(gnus-uncompress-range mark-list))
|
||||
(range-uncompress mark-list))
|
||||
(mapcar
|
||||
(lambda (id)
|
||||
(when (memq (cdr id) mark-list)
|
||||
@ -866,16 +866,16 @@ article came from is also searched."
|
||||
(when (and (gnus-check-backend-function
|
||||
'request-set-mark artgroup)
|
||||
(not (gnus-article-unpropagatable-p type)))
|
||||
(let* ((old (gnus-list-range-intersection
|
||||
(let* ((old (range-list-intersection
|
||||
artlist
|
||||
(alist-get type (gnus-info-marks group-info))))
|
||||
(del (gnus-remove-from-range (copy-tree old) list))
|
||||
(add (gnus-remove-from-range (copy-tree list) old)))
|
||||
(del (range-remove (copy-tree old) list))
|
||||
(add (range-remove (copy-tree list) old)))
|
||||
(when add (push (list add 'add (list type)) delta-marks))
|
||||
(when del
|
||||
;; Don't delete marks from outside the active range.
|
||||
;; This shouldn't happen, but is a sanity check.
|
||||
(setq del (gnus-sorted-range-intersection
|
||||
(setq del (range-intersection
|
||||
(gnus-active artgroup) del))
|
||||
(push (list del 'del (list type)) delta-marks))))
|
||||
|
||||
@ -910,18 +910,18 @@ article came from is also searched."
|
||||
(< (car elt1) (car elt2))))))
|
||||
(t
|
||||
(setq list
|
||||
(gnus-compress-sequence
|
||||
(range-compress-list
|
||||
(gnus-sorted-union
|
||||
(gnus-sorted-difference
|
||||
(gnus-uncompress-sequence
|
||||
(alist-get type (gnus-info-marks group-info)))
|
||||
artlist)
|
||||
(sort list #'<)) t)))
|
||||
(sort list #'<)))))
|
||||
|
||||
;; When exiting the group, everything that's previously been
|
||||
;; unseen is now seen.
|
||||
(when (eq type 'seen)
|
||||
(setq list (gnus-range-add
|
||||
(setq list (range-concat
|
||||
list (cdr (assoc artgroup select-unseen))))))
|
||||
|
||||
(when (or list (eq type 'unexist))
|
||||
@ -944,9 +944,9 @@ article came from is also searched."
|
||||
;; update read and unread
|
||||
(gnus-update-read-articles
|
||||
artgroup
|
||||
(gnus-uncompress-range
|
||||
(gnus-add-to-range
|
||||
(gnus-remove-from-range
|
||||
(range-uncompress
|
||||
(range-add-list
|
||||
(range-remove
|
||||
old-unread
|
||||
(cdr (assoc artgroup select-reads)))
|
||||
(sort (cdr (assoc artgroup select-unreads)) #'<))))
|
||||
|
@ -365,7 +365,7 @@ It is computed from the marks of individual component groups.")
|
||||
(lambda (article)
|
||||
(nnvirtual-reverse-map-article
|
||||
group article))
|
||||
(gnus-uncompress-range
|
||||
(range-uncompress
|
||||
(gnus-group-expire-articles-1 group))))))
|
||||
(sort (delq nil unexpired) #'<)))
|
||||
|
||||
|
@ -496,9 +496,16 @@ suitable file is found, return nil."
|
||||
(let ((pt2 (with-current-buffer standard-output (point)))
|
||||
(remapped (command-remapping function)))
|
||||
(unless (memq remapped '(ignore undefined))
|
||||
(let ((keys (where-is-internal
|
||||
(or remapped function) overriding-local-map nil nil))
|
||||
non-modified-keys)
|
||||
(let* ((all-keys (where-is-internal
|
||||
(or remapped function) overriding-local-map nil nil))
|
||||
(seps (seq-group-by
|
||||
(lambda (key)
|
||||
(and (vectorp key)
|
||||
(eq (elt key 0) 'menu-bar)))
|
||||
all-keys))
|
||||
(keys (cdr (assq nil seps)))
|
||||
(menus (cdr (assq t seps)))
|
||||
non-modified-keys)
|
||||
(if (and (eq function 'self-insert-command)
|
||||
(vectorp (car-safe keys))
|
||||
(consp (aref (car keys) 0)))
|
||||
@ -522,24 +529,42 @@ suitable file is found, return nil."
|
||||
;; don't mention them one by one.
|
||||
(if (< (length non-modified-keys) 10)
|
||||
(with-current-buffer standard-output
|
||||
(insert (mapconcat #'help--key-description-fontified
|
||||
keys ", ")))
|
||||
(help-fns--insert-bindings keys))
|
||||
(dolist (key non-modified-keys)
|
||||
(setq keys (delq key keys)))
|
||||
(if keys
|
||||
(with-current-buffer standard-output
|
||||
(insert (mapconcat #'help--key-description-fontified
|
||||
keys ", "))
|
||||
(help-fns--insert-bindings keys)
|
||||
(insert ", and many ordinary text characters"))
|
||||
(princ "many ordinary text characters"))))
|
||||
(princ "many ordinary text characters."))))
|
||||
(when (or remapped keys non-modified-keys)
|
||||
(princ ".")
|
||||
(terpri)))))
|
||||
(terpri)))
|
||||
|
||||
(with-current-buffer standard-output
|
||||
(fill-region-as-paragraph pt2 (point))
|
||||
(unless (looking-back "\n\n" (- (point) 2))
|
||||
(terpri))))))
|
||||
(with-current-buffer standard-output
|
||||
(fill-region-as-paragraph pt2 (point))
|
||||
(unless (bolp)
|
||||
(insert "\n"))
|
||||
(when menus
|
||||
(let ((start (point)))
|
||||
(insert (concat "It can "
|
||||
(and keys "also ")
|
||||
"be invoked from the menu: "))
|
||||
;; FIXME: Should insert menu names instead of key
|
||||
;; binding names.
|
||||
(help-fns--insert-bindings menus)
|
||||
(insert ".")
|
||||
(fill-region-as-paragraph start (point))))
|
||||
(ensure-empty-lines)))))))
|
||||
|
||||
(defun help-fns--insert-bindings (keys)
|
||||
(seq-do-indexed (lambda (key i)
|
||||
(insert
|
||||
(cond ((zerop i) "")
|
||||
((= i (1- (length keys))) " and ")
|
||||
(t ", ")))
|
||||
(insert (help--key-description-fontified key)))
|
||||
keys))
|
||||
|
||||
(defun help-fns--compiler-macro (function)
|
||||
(let ((handler (function-get function 'compiler-macro)))
|
||||
|
@ -727,11 +727,12 @@ with completion and history."
|
||||
(cdr (member last-used-face hi-lock-face-defaults))
|
||||
hi-lock-face-defaults))
|
||||
face)
|
||||
(if (and hi-lock-auto-select-face (not current-prefix-arg))
|
||||
(if (and hi-lock-auto-select-face (not current-prefix-arg))
|
||||
(setq face (or (pop hi-lock--unused-faces) (car defaults)))
|
||||
(setq face (completing-read
|
||||
(format-prompt "Highlight using face" (car defaults))
|
||||
obarray 'facep t nil 'face-name-history defaults))
|
||||
(setq face (symbol-name
|
||||
(read-face-name
|
||||
(format-prompt "Highlight using face" (car defaults))
|
||||
defaults)))
|
||||
;; Update list of un-used faces.
|
||||
(setq hi-lock--unused-faces (remove face hi-lock--unused-faces))
|
||||
;; Grow the list of defaults.
|
||||
@ -855,7 +856,8 @@ SPACES-REGEXP is a regexp to substitute spaces in font-lock search."
|
||||
nil)
|
||||
|
||||
;;; Mouse support
|
||||
(defun hi-lock-symbol-at-mouse (event)
|
||||
(defalias 'highlight-symbol-at-mouse 'hi-lock-face-symbol-at-mouse)
|
||||
(defun hi-lock-face-symbol-at-mouse (event)
|
||||
"Highlight symbol at mouse click EVENT."
|
||||
(interactive "e")
|
||||
(save-excursion
|
||||
@ -865,13 +867,13 @@ SPACES-REGEXP is a regexp to substitute spaces in font-lock search."
|
||||
;;;###autoload
|
||||
(defun hi-lock-context-menu (menu click)
|
||||
"Populate MENU with a menu item to highlight symbol at CLICK."
|
||||
(save-excursion
|
||||
(mouse-set-point click)
|
||||
(when (symbol-at-point)
|
||||
(define-key-after menu [highlight-search-separator] menu-bar-separator)
|
||||
(define-key-after menu [highlight-search-mouse]
|
||||
'(menu-item "Highlight Symbol" highlight-symbol-at-mouse
|
||||
:help "Highlight symbol at point"))))
|
||||
(when (thing-at-mouse click 'symbol)
|
||||
(define-key-after menu [highlight-search-separator] menu-bar-separator
|
||||
'middle-separator)
|
||||
(define-key-after menu [highlight-search-mouse]
|
||||
'(menu-item "Highlight Symbol" highlight-symbol-at-mouse
|
||||
:help "Highlight symbol at point")
|
||||
'highlight-search-separator))
|
||||
menu)
|
||||
|
||||
(provide 'hi-lock)
|
||||
|
@ -2353,7 +2353,8 @@ for deletion instead."
|
||||
(interactive)
|
||||
(image-dired--with-marked
|
||||
(image-dired-delete-char)
|
||||
(backward-char))
|
||||
(unless (bobp)
|
||||
(backward-char)))
|
||||
(image-dired--line-up-with-method)
|
||||
(with-current-buffer (image-dired-associated-dired-buffer)
|
||||
(dired-do-delete)))
|
||||
|
@ -77,10 +77,11 @@ This variable has no effect unless `tab-always-indent' is `complete'."
|
||||
:group 'indent
|
||||
:type '(choice
|
||||
(const :tag "Always complete" nil)
|
||||
(const :tag "Unless at the end of a line" 'eol)
|
||||
(const :tag "Unless looking at a word" 'word)
|
||||
(const :tag "Unless at a word or parenthesis" 'word-or-paren)
|
||||
(const :tag "Unless at a word, parenthesis, or punctuation." 'word-or-paren-or-punct))
|
||||
(const :tag "Unless at the end of a line" eol)
|
||||
(const :tag "Unless looking at a word" word)
|
||||
(const :tag "Unless at a word or parenthesis" word-or-paren)
|
||||
(const :tag "Unless at a word, parenthesis, or punctuation."
|
||||
word-or-paren-or-punct))
|
||||
:version "28.1")
|
||||
|
||||
(defvar indent-line-ignored-functions '(indent-relative
|
||||
@ -170,7 +171,7 @@ prefix argument is ignored."
|
||||
(let ((old-tick (buffer-chars-modified-tick))
|
||||
(old-point (point))
|
||||
(old-indent (current-indentation))
|
||||
(syn `(,(syntax-after (point)))))
|
||||
(syn (syntax-after (point))))
|
||||
|
||||
;; Indent the line.
|
||||
(or (not (eq (indent--funcall-widened indent-line-function) 'noindent))
|
||||
@ -182,21 +183,21 @@ prefix argument is ignored."
|
||||
(cond
|
||||
;; If the text was already indented right, try completion.
|
||||
((and (eq tab-always-indent 'complete)
|
||||
(eq old-point (point))
|
||||
(eq old-tick (buffer-chars-modified-tick))
|
||||
(eql old-point (point))
|
||||
(eql old-tick (buffer-chars-modified-tick))
|
||||
(or (null tab-first-completion)
|
||||
(eq last-command this-command)
|
||||
(and (equal tab-first-completion 'eol)
|
||||
(and (eq tab-first-completion 'eol)
|
||||
(eolp))
|
||||
(and (member tab-first-completion
|
||||
'(word word-or-paren word-or-paren-or-punct))
|
||||
(not (member 2 syn)))
|
||||
(and (member tab-first-completion
|
||||
'(word-or-paren word-or-paren-or-punct))
|
||||
(not (or (member 4 syn)
|
||||
(member 5 syn))))
|
||||
(and (equal tab-first-completion 'word-or-paren-or-punct)
|
||||
(not (member 1 syn)))))
|
||||
(and (memq tab-first-completion
|
||||
'(word word-or-paren word-or-paren-or-punct))
|
||||
(not (eql 2 syn)))
|
||||
(and (memq tab-first-completion
|
||||
'(word-or-paren word-or-paren-or-punct))
|
||||
(not (or (eql 4 syn)
|
||||
(eql 5 syn))))
|
||||
(and (eq tab-first-completion 'word-or-paren-or-punct)
|
||||
(not (eql 1 syn)))))
|
||||
(completion-at-point))
|
||||
|
||||
;; If a prefix argument was given, rigidly indent the following
|
||||
|
@ -1440,6 +1440,10 @@ Setup `char-width-table' appropriate for non-CJK language environment."
|
||||
(set-char-table-range char-script-table range 'tibetan))
|
||||
'tibetan)
|
||||
|
||||
;; Fix some exceptions that blocks.awk/Blocks.txt couldn't get right.
|
||||
(set-char-table-range char-script-table '(#x2ea . #x2eb) 'bopomofo)
|
||||
(set-char-table-range char-script-table #xab65 'greek)
|
||||
|
||||
|
||||
;;; Setting unicode-category-table.
|
||||
|
||||
@ -1522,8 +1526,11 @@ Setup `char-width-table' appropriate for non-CJK language environment."
|
||||
|
||||
;; We can't use the \N{name} things here, because this file is used
|
||||
;; too early in the build process.
|
||||
(defvar glyphless--bidi-control-characters
|
||||
'(#x202a ; ?\N{left-to-right embedding}
|
||||
(defvar bidi-control-characters
|
||||
'(#x200e ; ?\N{left-to-right mark}
|
||||
#x200f ; ?\N{right-to-left mark}
|
||||
#x061c ; ?\N{arabic letter mark}
|
||||
#x202a ; ?\N{left-to-right embedding}
|
||||
#x202b ; ?\N{right-to-left embedding}
|
||||
#x202d ; ?\N{left-to-right override}
|
||||
#x202e ; ?\N{right-to-left override}
|
||||
@ -1531,7 +1538,14 @@ Setup `char-width-table' appropriate for non-CJK language environment."
|
||||
#x2067 ; ?\N{right-to-left isolate}
|
||||
#x2068 ; ?\N{first strong isolate}
|
||||
#x202c ; ?\N{pop directional formatting}
|
||||
#x2069)) ; ?\N{pop directional isolate})
|
||||
#x2069) ; ?\N{pop directional isolate}
|
||||
"List of bidirectional control characters.")
|
||||
|
||||
(defun bidi-string-strip-control-characters (string)
|
||||
"Strip bidi control characters from STRING and return the result."
|
||||
(apply #'string (seq-filter (lambda (char)
|
||||
(not (memq char bidi-control-characters)))
|
||||
string)))
|
||||
|
||||
(defun update-glyphless-char-display (&optional variable value)
|
||||
"Make the setting of `glyphless-char-display-control' take effect.
|
||||
@ -1578,8 +1592,7 @@ option `glyphless-char-display'."
|
||||
(or (aref char-acronym-table from)
|
||||
"UNK")))
|
||||
(when (or (eq target 'format-control)
|
||||
(memq from
|
||||
glyphless--bidi-control-characters))
|
||||
(memq from bidi-control-characters))
|
||||
(set-char-table-range glyphless-char-display
|
||||
from this-method)))
|
||||
(setq from (1+ from))))))
|
||||
|
@ -55,6 +55,14 @@
|
||||
"Face for emojis that have derivations."
|
||||
:version "29.1")
|
||||
|
||||
(defvar emoji-alternate-names nil
|
||||
"Alist of emojis and lists of alternate names for the emojis.
|
||||
Each element in the alist should have the emoji (as a string) as
|
||||
the first element, and the rest of the elements should be strings
|
||||
representing names. For instance:
|
||||
|
||||
(\"🤗\" \"hug\" \"hugging\" \"kind\")")
|
||||
|
||||
(defvar emoji--labels nil)
|
||||
(defvar emoji--all-bases nil)
|
||||
(defvar emoji--derived nil)
|
||||
@ -90,8 +98,9 @@ of selecting from emoji display."
|
||||
;;;###autoload
|
||||
(defun emoji-search ()
|
||||
"Choose and insert an emoji glyph by typing its Unicode name.
|
||||
This command prompts for an emoji name, with completion, and inserts it.
|
||||
It recognizes the Unicode Standard names of emoji."
|
||||
This command prompts for an emoji name, with completion, and
|
||||
inserts it. It recognizes the Unicode Standard names of emoji,
|
||||
and also consults the `emoji-alternate-names' alist."
|
||||
(interactive "*")
|
||||
(emoji--init)
|
||||
(emoji--choose-emoji))
|
||||
@ -647,29 +656,47 @@ We prefer the earliest unique letter."
|
||||
|
||||
(defun emoji--choose-emoji ()
|
||||
;; Use the list of names.
|
||||
(let ((name
|
||||
(completing-read
|
||||
"Insert emoji: "
|
||||
(lambda (string pred action)
|
||||
(if (eq action 'metadata)
|
||||
(list 'metadata
|
||||
(cons
|
||||
'affixation-function
|
||||
;; Add the glyphs to the start of the displayed
|
||||
;; strings when TAB-ing.
|
||||
(lambda (strings)
|
||||
(mapcar
|
||||
(lambda (name)
|
||||
(list name
|
||||
(concat
|
||||
(or (gethash name emoji--all-bases) " ")
|
||||
"\t")
|
||||
""))
|
||||
strings))))
|
||||
(complete-with-action action emoji--all-bases string pred)))
|
||||
nil t)))
|
||||
(let* ((table
|
||||
(if (not emoji-alternate-names)
|
||||
;; If we don't have alternate names, do the efficient version.
|
||||
emoji--all-bases
|
||||
;; Compute all the (possibly non-unique) names.
|
||||
(let ((table nil))
|
||||
(maphash
|
||||
(lambda (name glyph)
|
||||
(push (concat name "\t" glyph) table))
|
||||
emoji--all-bases)
|
||||
(dolist (elem emoji-alternate-names)
|
||||
(dolist (name (cdr elem))
|
||||
(push (concat name "\t" (car elem)) table)))
|
||||
(sort table #'string<))))
|
||||
(name
|
||||
(completing-read
|
||||
"Insert emoji: "
|
||||
(lambda (string pred action)
|
||||
(if (eq action 'metadata)
|
||||
(list 'metadata
|
||||
(cons
|
||||
'affixation-function
|
||||
;; Add the glyphs to the start of the displayed
|
||||
;; strings when TAB-ing.
|
||||
(lambda (strings)
|
||||
(mapcar
|
||||
(lambda (name)
|
||||
(if emoji-alternate-names
|
||||
(list name "" "")
|
||||
(list name
|
||||
(concat
|
||||
(or (gethash name emoji--all-bases) " ")
|
||||
"\t")
|
||||
"")))
|
||||
strings))))
|
||||
(complete-with-action action table string pred)))
|
||||
nil t)))
|
||||
(when (cl-plusp (length name))
|
||||
(let* ((glyph (gethash name emoji--all-bases))
|
||||
(let* ((glyph (if emoji-alternate-names
|
||||
(cadr (split-string name "\t"))
|
||||
(gethash name emoji--all-bases)))
|
||||
(derived (gethash glyph emoji--derived)))
|
||||
(if (not derived)
|
||||
;; Simple glyph with no derivations.
|
||||
|
@ -231,7 +231,6 @@
|
||||
(elymaic #x10FE0)
|
||||
(old-uyghur #x10F70)
|
||||
(mahajani #x11150)
|
||||
(sinhala-archaic-number #x111E1)
|
||||
(khojki #x11200)
|
||||
(khudawadi #x112B0)
|
||||
(grantha #x11305)
|
||||
@ -253,7 +252,6 @@
|
||||
(gunjala-gondi #x11D60)
|
||||
(makasar #x11EE0)
|
||||
(cuneiform #x12000)
|
||||
(cuneiform-numbers-and-punctuation #x12400)
|
||||
(cypro-minoan #x12F90)
|
||||
(egyptian #x13000)
|
||||
(mro #x16A40)
|
||||
@ -262,7 +260,6 @@
|
||||
(pahawh-hmong #x16B11)
|
||||
(medefaidrin #x16E40)
|
||||
(tangut #x17000)
|
||||
(tangut-components #x18800)
|
||||
(khitan-small-script #x18B00)
|
||||
(nushu #x1B170)
|
||||
(duployan-shorthand #x1BC20)
|
||||
@ -768,7 +765,6 @@
|
||||
old-uyghur
|
||||
makasar
|
||||
dives-akuru
|
||||
cuneiform-numbers-and-punctuation
|
||||
cuneiform
|
||||
egyptian
|
||||
tangsa
|
||||
|
78
lisp/international/textsec-check.el
Normal file
78
lisp/international/textsec-check.el
Normal file
@ -0,0 +1,78 @@
|
||||
;;; textsec-check.el --- Check for suspicious texts -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup textsec nil
|
||||
"Suspicious text identification."
|
||||
:group 'security
|
||||
:version "29.1")
|
||||
|
||||
(defcustom textsec-check t
|
||||
"If non-nil, perform some security-related checks on text objects.
|
||||
If nil, these checks are disabled."
|
||||
:type 'boolean
|
||||
:version "29.1")
|
||||
|
||||
(defface textsec-suspicious
|
||||
'((t (:weight bold :background "red")))
|
||||
"Face used to highlight suspicious strings.")
|
||||
|
||||
;;;###autoload
|
||||
(defun textsec-suspicious-p (object type)
|
||||
"Say whether OBJECT is suspicious for use as TYPE.
|
||||
If OBJECT is suspicious, return a string explaining the reason
|
||||
for considering it suspicious, otherwise return nil.
|
||||
|
||||
Available values of TYPE and corresponding OBJECTs are:
|
||||
|
||||
`url' -- a URL; OBJECT should be a URL string.
|
||||
|
||||
`link' -- an HTML link; OBJECT should be a cons cell
|
||||
of the form (URL . LINK-TEXT).
|
||||
|
||||
`domain' -- a Web domain; OBJECT should be a string.
|
||||
|
||||
`local-address' -- the local part of an email address; OBJECT
|
||||
should be a string.
|
||||
`name' -- the \"display name\" part of an email address;
|
||||
OBJECT should be a string.
|
||||
|
||||
`email-address' -- a full email address; OBJECT should be a string.
|
||||
|
||||
`email-address-header' -- a raw email address header in RFC 2822 format;
|
||||
OBJECT should be a string.
|
||||
|
||||
If the user option `textsec-check' is nil, these checks are
|
||||
disabled, and this function always returns nil."
|
||||
(if (not textsec-check)
|
||||
nil
|
||||
(require 'textsec)
|
||||
(let ((func (intern (format "textsec-%s-suspicious-p" type))))
|
||||
(unless (fboundp func)
|
||||
(error "%s is not a valid function" func))
|
||||
(funcall func object))))
|
||||
|
||||
(provide 'textsec-check)
|
||||
|
||||
;;; textsec-check.el ends here
|
429
lisp/international/textsec.el
Normal file
429
lisp/international/textsec.el
Normal file
@ -0,0 +1,429 @@
|
||||
;;; textsec.el --- Functions for handling homoglyphs and the like -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'uni-confusable)
|
||||
(require 'ucs-normalize)
|
||||
(require 'idna-mapping)
|
||||
(require 'puny)
|
||||
(require 'mail-parse)
|
||||
(require 'url)
|
||||
|
||||
(defvar textsec--char-scripts nil)
|
||||
|
||||
(eval-and-compile
|
||||
(defun textsec--create-script-table (data)
|
||||
"Create the textsec--char-scripts char table."
|
||||
(setq textsec--char-scripts (make-char-table nil))
|
||||
(dolist (scripts data)
|
||||
(dolist (range (cadr scripts))
|
||||
(set-char-table-range textsec--char-scripts
|
||||
range (car scripts)))))
|
||||
(require 'uni-scripts))
|
||||
|
||||
(defun textsec-scripts (string)
|
||||
"Return a list of Unicode scripts used in STRING.
|
||||
The scripts returned by this function use the Unicode Script property
|
||||
as defined by the Unicode Standard Annex 24 (UAX#24)."
|
||||
(seq-map (lambda (char)
|
||||
(elt textsec--char-scripts char))
|
||||
string))
|
||||
|
||||
(defun textsec-single-script-p (string)
|
||||
"Return non-nil if STRING is all in a single Unicode script.
|
||||
|
||||
Note that the concept of \"single script\" used by this function
|
||||
isn't obvious -- some mixtures of scripts count as a \"single
|
||||
script\". See
|
||||
|
||||
https://www.unicode.org/reports/tr39/#Mixed_Script_Detection
|
||||
|
||||
for details. The Unicode scripts are as defined by the
|
||||
Unicode Standard Annex 24 (UAX#24)."
|
||||
(let ((scripts (mapcar
|
||||
(lambda (s)
|
||||
(append s
|
||||
;; Some scripts used in East Asia are
|
||||
;; commonly used across borders, so we add
|
||||
;; those.
|
||||
(mapcan (lambda (script)
|
||||
(copy-sequence
|
||||
(textsec--augment-script script)))
|
||||
s)))
|
||||
(textsec-scripts string))))
|
||||
(catch 'empty
|
||||
(cl-loop for s1 in scripts
|
||||
do (cl-loop for s2 in scripts
|
||||
;; Common/inherited chars can be used in
|
||||
;; text with all scripts.
|
||||
when (and (not (memq 'common s1))
|
||||
(not (memq 'common s2))
|
||||
(not (memq 'inherited s1))
|
||||
(not (memq 'inherited s2))
|
||||
(not (seq-intersection s1 s2)))
|
||||
do (throw 'empty nil)))
|
||||
t)))
|
||||
|
||||
(defun textsec--augment-script (script)
|
||||
(cond
|
||||
((eq script 'han)
|
||||
'(hangul japan korea))
|
||||
((or (eq script 'hiragana)
|
||||
(eq script 'katakana))
|
||||
'(japan))
|
||||
((or (eq script 'hangul)
|
||||
(eq script 'bopomofo))
|
||||
'(korea))))
|
||||
|
||||
(defun textsec-covering-scripts (string)
|
||||
"Return a minimal list of scripts used in STRING.
|
||||
Note that a string may have several different minimal cover sets.
|
||||
The scripts are as defined by the Unicode Standard Annex 24 (UAX#24)."
|
||||
(let* ((scripts (textsec-scripts string))
|
||||
(set (car scripts)))
|
||||
(dolist (s scripts)
|
||||
(setq set (seq-union set (seq-difference s set))))
|
||||
(sort (delq 'common (delq 'inherited set)) #'string<)))
|
||||
|
||||
(defun textsec-restriction-level (string)
|
||||
"Say what restriction level STRING qualifies for.
|
||||
Levels are (in decreasing order of restrictiveness) `ascii-only',
|
||||
`single-script', `highly-restrictive', `moderately-restrictive',
|
||||
`minimally-restrictive' and `unrestricted'."
|
||||
(let ((scripts (textsec-covering-scripts string)))
|
||||
(cond
|
||||
((string-match "\\`[[:ascii:]]+\\'" string)
|
||||
'ascii-only)
|
||||
((textsec-single-script-p string)
|
||||
'single-script)
|
||||
((or (null (seq-difference scripts '(latin han hiragana katakana)))
|
||||
(null (seq-difference scripts '(latin han bopomofo)))
|
||||
(null (seq-difference scripts '(latin han hangul))))
|
||||
'highly-restrictive)
|
||||
((and (= (length scripts) 2)
|
||||
(memq 'latin scripts)
|
||||
;; This list comes from
|
||||
;; https://www.unicode.org/reports/tr31/#Table_Recommended_Scripts
|
||||
;; (but without latin, cyrillic and greek).
|
||||
(seq-intersection scripts
|
||||
'(arabic
|
||||
armenian
|
||||
bengali
|
||||
bopomofo
|
||||
devanagari
|
||||
ethiopic
|
||||
georgian
|
||||
gujarati
|
||||
gurmukhi
|
||||
hangul
|
||||
han
|
||||
hebrew
|
||||
hiragana
|
||||
katakana
|
||||
kannada
|
||||
khmer
|
||||
lao
|
||||
malayalam
|
||||
myanmar
|
||||
oriya
|
||||
sinhala
|
||||
tamil
|
||||
telugu
|
||||
thaana
|
||||
thai
|
||||
tibetan)))
|
||||
;; The string is covered by Latin and any one other Recommended
|
||||
;; script, except Cyrillic, Greek.
|
||||
'moderately-retrictive)
|
||||
;; Fixme `minimally-restrictive' -- needs well-formedness criteria
|
||||
;; and Identifier Profile.
|
||||
(t
|
||||
'unrestricted))))
|
||||
|
||||
(defun textsec-mixed-numbers-p (string)
|
||||
"Return non-nil if STRING includes numbers from different decimal systems."
|
||||
(>
|
||||
(length
|
||||
(seq-uniq
|
||||
(mapcar
|
||||
(lambda (char)
|
||||
;; Compare zeros in the respective decimal systems.
|
||||
(- char (get-char-code-property char 'numeric-value)))
|
||||
(seq-filter (lambda (char)
|
||||
;; We're selecting the characters that
|
||||
;; have a numeric property.
|
||||
(eq (get-char-code-property char 'general-category)
|
||||
'Nd))
|
||||
string))))
|
||||
1))
|
||||
|
||||
(defun textsec-ascii-confusable-p (string)
|
||||
"Return non-nil if non-ASCII STRING can be confused with ASCII on display."
|
||||
(and (not (eq (textsec-restriction-level string) 'ascii-only))
|
||||
(eq (textsec-restriction-level (textsec-unconfuse-string string))
|
||||
'ascii-only)))
|
||||
|
||||
(defun textsec-unconfuse-string (string)
|
||||
"Return a de-confused version of STRING.
|
||||
This algorithm is described in:
|
||||
|
||||
https://www.unicode.org/reports/tr39/#Confusable_Detection"
|
||||
(ucs-normalize-NFD-string
|
||||
(apply #'concat
|
||||
(seq-map (lambda (char)
|
||||
(or (gethash char uni-confusable-table)
|
||||
(string char)))
|
||||
(ucs-normalize-NFD-string string)))))
|
||||
|
||||
(defun textsec-resolved-script-set (string)
|
||||
"Return the resolved script set for STRING.
|
||||
This is the minimal covering script set for STRING, but is nil is
|
||||
STRING isn't a single script string.
|
||||
The scripts are as defined by the Unicode Standard Annex 24 (UAX#24)."
|
||||
(and (textsec-single-script-p string)
|
||||
(textsec-covering-scripts string)))
|
||||
|
||||
(defun textsec-single-script-confusable-p (string1 string2)
|
||||
"Say whether STRING1 and STRING2 are single-script confusables.
|
||||
The scripts are as defined by the Unicode Standard Annex 24 (UAX#24)."
|
||||
(and (equal (textsec-unconfuse-string string1)
|
||||
(textsec-unconfuse-string string2))
|
||||
;; And they have to have at least one resolved script in
|
||||
;; common.
|
||||
(seq-intersection (textsec-resolved-script-set string1)
|
||||
(textsec-resolved-script-set string2))))
|
||||
|
||||
(defun textsec-mixed-script-confusable-p (string1 string2)
|
||||
"Say whether STRING1 and STRING2 are mixed-script confusables.
|
||||
The scripts are as defined by the Unicode Standard Annex 24 (UAX#24)."
|
||||
(and (equal (textsec-unconfuse-string string1)
|
||||
(textsec-unconfuse-string string2))
|
||||
;; And they have no resolved scripts in common.
|
||||
(null (seq-intersection (textsec-resolved-script-set string1)
|
||||
(textsec-resolved-script-set string2)))))
|
||||
|
||||
(defun textsec-whole-script-confusable-p (string1 string2)
|
||||
"Say whether STRING1 and STRING2 are whole-script confusables.
|
||||
The scripts are as defined by the Unicode Standard Annex 24 (UAX#24)."
|
||||
(and (textsec-mixed-script-confusable-p string1 string2)
|
||||
(textsec-single-script-p string1)
|
||||
(textsec-single-script-p string2)))
|
||||
|
||||
(defun textsec-domain-suspicious-p (domain)
|
||||
"Say whether DOMAIN's name looks suspicious.
|
||||
Return nil if it isn't suspicious. If it is, return a string explaining
|
||||
the potential problem.
|
||||
|
||||
Domain names are considered suspicious if they use characters
|
||||
that can look similar to other characters when displayed, or
|
||||
use characters that are not allowed by Unicode's IDNA mapping,
|
||||
or use certain other unusual mixtures of characters."
|
||||
(catch 'found
|
||||
(seq-do
|
||||
(lambda (char)
|
||||
(when (eq (elt idna-mapping-table char) t)
|
||||
(throw 'found
|
||||
(format "Disallowed character%s (#x%x, %s)"
|
||||
(if (eq (get-char-code-property char 'general-category)
|
||||
'Cf)
|
||||
""
|
||||
(concat ": " (string char)))
|
||||
char
|
||||
(get-char-code-property char 'name)))))
|
||||
domain)
|
||||
;; Does IDNA allow it?
|
||||
(unless (puny-highly-restrictive-domain-p domain)
|
||||
(throw
|
||||
'found
|
||||
(format "`%s' mixes characters from different scripts in suspicious ways"
|
||||
domain)))
|
||||
;; Check whether any segment of the domain name is confusable with
|
||||
;; an ASCII-only segment.
|
||||
(dolist (elem (split-string domain "\\."))
|
||||
(when (textsec-ascii-confusable-p elem)
|
||||
(throw 'found (format "`%s' is confusable with ASCII" elem))))
|
||||
nil))
|
||||
|
||||
(defun textsec-local-address-suspicious-p (local)
|
||||
"Say whether LOCAL part of an email address looks suspicious.
|
||||
LOCAL is the bit before \"@\" in an email address.
|
||||
|
||||
If it isn't suspicious, return nil. If it is, return a string explaining
|
||||
the potential problem.
|
||||
|
||||
Email addresses are considered suspicious if they use characters
|
||||
that can look similar to other characters when displayed, or use
|
||||
certain other unusual mixtures of characters."
|
||||
(cond
|
||||
((not (equal local (ucs-normalize-NFKC-string local)))
|
||||
(format "`%s' is not in normalized format `%s'"
|
||||
local (ucs-normalize-NFKC-string local)))
|
||||
((textsec-mixed-numbers-p local)
|
||||
(format "`%s' contains numbers from different number systems" local))
|
||||
((eq (textsec-restriction-level local) 'unrestricted)
|
||||
(format "`%s' isn't restrictive enough" local))
|
||||
((string-match-p "\\`\\.\\|\\.\\'\\|\\.\\." local)
|
||||
(format "`%s' contains invalid dots" local))))
|
||||
|
||||
(defun textsec-name-suspicious-p (name)
|
||||
"Say whether NAME looks suspicious.
|
||||
NAME is (for instance) the free-text display name part of an
|
||||
email address.
|
||||
|
||||
If it isn't suspicious, return nil. If it is, return a string
|
||||
explaining the potential problem.
|
||||
|
||||
Names are considered suspicious if they use characters that can
|
||||
look similar to other characters when displayed, or use certain
|
||||
other unusual mixtures of characters."
|
||||
(cond
|
||||
((not (equal name (ucs-normalize-NFC-string name)))
|
||||
(format "`%s' is not in normalized format `%s'"
|
||||
name (ucs-normalize-NFC-string name)))
|
||||
((and (seq-find (lambda (char)
|
||||
(and (member char bidi-control-characters)
|
||||
(not (member char
|
||||
'( ?\N{left-to-right mark}
|
||||
?\N{right-to-left mark}
|
||||
?\N{arabic letter mark})))))
|
||||
name)
|
||||
;; We have bidirectional formatting characters, but check
|
||||
;; whether they affect LTR characters. If not, it's not
|
||||
;; suspicious.
|
||||
(bidi-find-overridden-directionality 0 (length name) name))
|
||||
(format "The string contains bidirectional control characters"))
|
||||
((textsec-suspicious-nonspacing-p name))))
|
||||
|
||||
(defun textsec-suspicious-nonspacing-p (string)
|
||||
"Say whether STRING uses nonspacing characters in suspicious ways.
|
||||
If it doesn't, return nil. If it does, return a string explaining
|
||||
the potential problem.
|
||||
|
||||
Use of nonspacing characters is considered suspicious if there are
|
||||
two or more consecutive identical nonspacing characters, or too many
|
||||
consecutive nonspacing characters."
|
||||
(let ((prev nil)
|
||||
(nonspace-count 0))
|
||||
(catch 'found
|
||||
(seq-do
|
||||
(lambda (char)
|
||||
(let ((nonspacing
|
||||
(memq (get-char-code-property char 'general-category)
|
||||
'(Mn Me))))
|
||||
(when (and nonspacing
|
||||
(equal char prev))
|
||||
(throw 'found "Two identical consecutive nonspacing characters"))
|
||||
(setq nonspace-count (if nonspacing
|
||||
(1+ nonspace-count)
|
||||
0))
|
||||
(when (> nonspace-count 4)
|
||||
(throw 'found
|
||||
"Too many consecutive nonspacing characters"))
|
||||
(setq prev char)))
|
||||
string)
|
||||
nil)))
|
||||
|
||||
(defun textsec-email-address-suspicious-p (address)
|
||||
"Say whether EMAIL address looks suspicious.
|
||||
If it isn't, return nil. If it is, return a string explaining the
|
||||
potential problem.
|
||||
|
||||
An email address is considered suspicious if either of its two
|
||||
parts -- the local address name or the domain -- are found to be
|
||||
suspicious by, respectively, `textsec-local-address-suspicious-p'
|
||||
and `textsec-domain-suspicious-p'."
|
||||
(pcase-let ((`(,local ,domain) (split-string address "@")))
|
||||
(or
|
||||
(textsec-domain-suspicious-p domain)
|
||||
(textsec-local-address-suspicious-p local))))
|
||||
|
||||
(defun textsec-email-address-header-suspicious-p (email)
|
||||
"Say whether EMAIL looks suspicious.
|
||||
If it isn't, return nil. If it is, return a string explaining the
|
||||
potential problem.
|
||||
|
||||
Note that EMAIL has to be a valid email specification according
|
||||
to RFC2047bis -- strings that can't be parsed will be flagged as
|
||||
suspicious.
|
||||
|
||||
An email specification is considered suspicious if either of its
|
||||
two parts -- the address or the name -- are found to be
|
||||
suspicious by, respectively, `textsec-email-address-suspicious-p'
|
||||
and `textsec-name-suspicious-p'."
|
||||
(catch 'end
|
||||
(pcase-let ((`(,address . ,name)
|
||||
(condition-case nil
|
||||
(mail-header-parse-address email t)
|
||||
(error (throw 'end "Email address can't be parsed.")))))
|
||||
(or
|
||||
(textsec-email-address-suspicious-p address)
|
||||
(and name (textsec-name-suspicious-p name))))))
|
||||
|
||||
(defun textsec-url-suspicious-p (url)
|
||||
"Say whether URL looks suspicious.
|
||||
If it isn't, return nil. If it is, return a string explaining the
|
||||
potential problem."
|
||||
(let ((parsed (url-generic-parse-url url)))
|
||||
;; The URL may not have a domain.
|
||||
(and (url-host parsed)
|
||||
(textsec-domain-suspicious-p (url-host parsed)))))
|
||||
|
||||
(defun textsec-link-suspicious-p (link)
|
||||
"Say whether LINK is suspicious.
|
||||
LINK should be a cons cell where the first element is the URL,
|
||||
and the second element is the link text.
|
||||
|
||||
This function will return non-nil if it seems like the link text
|
||||
is misleading about where the URL takes you. This is typical
|
||||
when the link text looks like an URL itself, but doesn't lead to
|
||||
the same domain as the URL."
|
||||
(let* ((url (car link))
|
||||
(text (string-trim (cdr link))))
|
||||
(catch 'found
|
||||
(let ((udomain (url-host (url-generic-parse-url url)))
|
||||
(tdomain (url-host (url-generic-parse-url text))))
|
||||
(cond
|
||||
((and udomain
|
||||
tdomain
|
||||
(not (equal udomain tdomain))
|
||||
;; One may be a sub-domain of the other, but don't allow too
|
||||
;; short domains.
|
||||
(not (or (and (string-suffix-p udomain tdomain)
|
||||
(url-domsuf-cookie-allowed-p udomain))
|
||||
(and (string-suffix-p tdomain udomain)
|
||||
(url-domsuf-cookie-allowed-p tdomain)))))
|
||||
(throw 'found
|
||||
(format "Text `%s' doesn't point to link URL `%s'"
|
||||
text url)))
|
||||
((and tdomain
|
||||
(textsec-domain-suspicious-p tdomain))
|
||||
(throw 'found
|
||||
(format "Domain `%s' in the link text is suspicious"
|
||||
(bidi-string-strip-control-characters
|
||||
tdomain)))))))))
|
||||
|
||||
(provide 'textsec)
|
||||
|
||||
;;; textsec.el ends here
|
@ -325,38 +325,38 @@ which is
|
||||
|
||||
Alt-Control-Hyper-Meta-Shift-super"
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(and
|
||||
(stringp keys)
|
||||
(string-match-p "\\`[^ ]+\\( [^ ]+\\)*\\'" keys)
|
||||
(save-match-data
|
||||
(catch 'exit
|
||||
(let ((prefixes
|
||||
"\\(A-\\)?\\(C-\\)?\\(H-\\)?\\(M-\\)?\\(S-\\)?\\(s-\\)?")
|
||||
(case-fold-search nil))
|
||||
(dolist (key (split-string keys " "))
|
||||
;; Every key might have these modifiers, and they should be
|
||||
;; in this order.
|
||||
(when (string-match (concat "\\`" prefixes) key)
|
||||
(setq key (substring key (match-end 0))))
|
||||
(unless (or (and (= (length key) 1)
|
||||
;; Don't accept control characters as keys.
|
||||
(not (< (aref key 0) ?\s))
|
||||
;; Don't accept Meta'd characters as keys.
|
||||
(or (multibyte-string-p key)
|
||||
(not (<= 127 (aref key 0) 255))))
|
||||
(and (string-match-p "\\`<[-_A-Za-z0-9]+>\\'" key)
|
||||
;; Don't allow <M-C-down>.
|
||||
(= (progn
|
||||
(string-match
|
||||
(concat "\\`<" prefixes) key)
|
||||
(match-end 0))
|
||||
1))
|
||||
(string-match-p
|
||||
"\\`\\(NUL\\|RET\\|TAB\\|LFD\\|ESC\\|SPC\\|DEL\\)\\'"
|
||||
key))
|
||||
;; Invalid.
|
||||
(throw 'exit nil)))
|
||||
t)))))
|
||||
(let ((case-fold-search nil))
|
||||
(and
|
||||
(stringp keys)
|
||||
(string-match-p "\\`[^ ]+\\( [^ ]+\\)*\\'" keys)
|
||||
(save-match-data
|
||||
(catch 'exit
|
||||
(let ((prefixes
|
||||
"\\(A-\\)?\\(C-\\)?\\(H-\\)?\\(M-\\)?\\(S-\\)?\\(s-\\)?"))
|
||||
(dolist (key (split-string keys " "))
|
||||
;; Every key might have these modifiers, and they should be
|
||||
;; in this order.
|
||||
(when (string-match (concat "\\`" prefixes) key)
|
||||
(setq key (substring key (match-end 0))))
|
||||
(unless (or (and (= (length key) 1)
|
||||
;; Don't accept control characters as keys.
|
||||
(not (< (aref key 0) ?\s))
|
||||
;; Don't accept Meta'd characters as keys.
|
||||
(or (multibyte-string-p key)
|
||||
(not (<= 127 (aref key 0) 255))))
|
||||
(and (string-match-p "\\`<[-_A-Za-z0-9]+>\\'" key)
|
||||
;; Don't allow <M-C-down>.
|
||||
(= (progn
|
||||
(string-match
|
||||
(concat "\\`<" prefixes) key)
|
||||
(match-end 0))
|
||||
1))
|
||||
(string-match-p
|
||||
"\\`\\(NUL\\|RET\\|TAB\\|LFD\\|ESC\\|SPC\\|DEL\\)\\'"
|
||||
key))
|
||||
;; Invalid.
|
||||
(throw 'exit nil)))
|
||||
t))))))
|
||||
|
||||
(defun key-translate (from to)
|
||||
"Translate character FROM to TO on the current terminal.
|
||||
|
10
lisp/man.el
10
lisp/man.el
@ -1993,11 +1993,13 @@ Uses `Man-name-local-regexp'."
|
||||
(skip-syntax-backward "^ ")
|
||||
(and (looking-at
|
||||
"[[:space:]]*\\([[:alnum:]_-]+([[:alnum:]]+)\\)")
|
||||
(match-string 1)))
|
||||
(define-key-after menu [man-separator] menu-bar-separator)
|
||||
(match-string 1)))
|
||||
(define-key-after menu [man-separator] menu-bar-separator
|
||||
'middle-separator)
|
||||
(define-key-after menu [man-at-mouse]
|
||||
'(menu-item "Open man page" man-at-mouse
|
||||
:help "Open man page around mouse click"))))
|
||||
'(menu-item "Open man page" Man-at-mouse
|
||||
:help "Open man page around mouse click")
|
||||
'man-separator)))
|
||||
menu)
|
||||
|
||||
|
||||
|
@ -96,26 +96,26 @@
|
||||
(bindings--define-key menu [separator-print]
|
||||
menu-bar-separator)
|
||||
|
||||
(unless (featurep 'ns)
|
||||
(bindings--define-key menu [close-tab]
|
||||
'(menu-item "Close Tab" tab-close
|
||||
:visible (fboundp 'tab-close)
|
||||
:help "Close currently selected tab"))
|
||||
(bindings--define-key menu [make-tab]
|
||||
'(menu-item "New Tab" tab-new
|
||||
:visible (fboundp 'tab-new)
|
||||
:help "Open a new tab"))
|
||||
(bindings--define-key menu [close-tab]
|
||||
'(menu-item "Close Tab" tab-close
|
||||
:visible (fboundp 'tab-close)
|
||||
:help "Close currently selected tab"))
|
||||
(bindings--define-key menu [make-tab]
|
||||
'(menu-item "New Tab" tab-new
|
||||
:visible (fboundp 'tab-new)
|
||||
:help "Open a new tab"))
|
||||
|
||||
(bindings--define-key menu [separator-tab]
|
||||
menu-bar-separator))
|
||||
(bindings--define-key menu [separator-tab]
|
||||
menu-bar-separator)
|
||||
|
||||
(bindings--define-key menu [undelete-frame-mode]
|
||||
'(menu-item "Allow Undeleting Frames" undelete-frame-mode
|
||||
:help "Allow frames to be restored after deletion"
|
||||
:button (:toggle . undelete-frame-mode)))
|
||||
|
||||
(bindings--define-key menu [enable-undelete-frame-mode]
|
||||
'(menu-item "Enable Undeleting Frames" undelete-frame-mode
|
||||
:visible (null undelete-frame-mode)
|
||||
:help "Enable undeleting frames in this session"))
|
||||
(bindings--define-key menu [undelete-last-deleted-frame]
|
||||
'(menu-item "Undelete Frame" undelete-frame
|
||||
:visible (and undelete-frame-mode
|
||||
:enable (and undelete-frame-mode
|
||||
(car undelete-frame--deleted-frames))
|
||||
:help "Undelete the most recently deleted frame"))
|
||||
|
||||
|
@ -1004,7 +1004,9 @@ an association list that can specify properties such as:
|
||||
- `styles': the list of `completion-styles' to use for that category.
|
||||
- `cycle': the `completion-cycle-threshold' to use for that category.
|
||||
Categories are symbols such as `buffer' and `file', used when
|
||||
completing buffer and file names, respectively.")
|
||||
completing buffer and file names, respectively.
|
||||
|
||||
Also see `completion-category-overrides'.")
|
||||
|
||||
(defcustom completion-category-overrides nil
|
||||
"List of category-specific user overrides for completion styles.
|
||||
@ -1014,7 +1016,9 @@ an association list that can specify properties such as:
|
||||
- `cycle': the `completion-cycle-threshold' to use for that category.
|
||||
Categories are symbols such as `buffer' and `file', used when
|
||||
completing buffer and file names, respectively.
|
||||
This overrides the defaults specified in `completion-category-defaults'."
|
||||
|
||||
If a property in a category is specified by this variable, it
|
||||
overrides the default specified in `completion-category-defaults'."
|
||||
:version "25.1"
|
||||
:type `(alist :key-type (choice :tag "Category"
|
||||
(const buffer)
|
||||
|
@ -298,9 +298,10 @@ and should return the same menu with changes such as added new menu items."
|
||||
(function-item context-menu-buffers)
|
||||
(function-item context-menu-vc)
|
||||
(function-item context-menu-ffap)
|
||||
(function-item Man-context-menu)
|
||||
(function-item hi-lock-context-menu)
|
||||
(function-item context-menu-online-search)
|
||||
(function-item occur-context-menu)
|
||||
(function-item Man-context-menu)
|
||||
(function-item dictionary-context-menu)
|
||||
(function :tag "Custom function")))
|
||||
:version "28.1")
|
||||
|
||||
@ -323,6 +324,8 @@ the function `context-menu-filter-function'."
|
||||
(fun (mouse-posn-property (event-start click)
|
||||
'context-menu-function)))
|
||||
|
||||
(select-window (posn-window (event-start click)))
|
||||
|
||||
(if (functionp fun)
|
||||
(setq menu (funcall fun menu click))
|
||||
(run-hook-wrapped 'context-menu-functions
|
||||
@ -534,16 +537,6 @@ Some context functions add menu items below the separator."
|
||||
:help "Find file or URL from text around mouse click"))))
|
||||
menu)
|
||||
|
||||
(defun context-menu-online-search (menu click)
|
||||
"Populate MENU with command to search online."
|
||||
(save-excursion
|
||||
(mouse-set-point click)
|
||||
(define-key-after menu [online-search-separator] menu-bar-separator)
|
||||
(define-key-after menu [online-search-at-mouse]
|
||||
'(menu-item "Online search" mouse-online-search-at-point
|
||||
:help "Search for region or word online")))
|
||||
menu)
|
||||
|
||||
(defvar context-menu-entry
|
||||
`(menu-item ,(purecopy "Context Menu") ,(make-sparse-keymap)
|
||||
:filter ,(lambda (_) (context-menu-map)))
|
||||
@ -3230,26 +3223,6 @@ is copied instead of being cut."
|
||||
(with-current-buffer (window-buffer window)
|
||||
(setq cursor-type (nth 3 state)))))))
|
||||
|
||||
(defvar eww-search-prefix)
|
||||
(defun mouse-online-search-at-point (event)
|
||||
"Query an online search engine at EVENT.
|
||||
If a region is active, the entire region will be sent, otherwise
|
||||
the symbol at point will be used. This command uses EWW's
|
||||
default search engine, as configured by `eww-search-prefix'."
|
||||
(interactive "e")
|
||||
(require 'eww)
|
||||
(let ((query (if (use-region-p)
|
||||
(buffer-substring (region-beginning)
|
||||
(region-end))
|
||||
(save-excursion
|
||||
(mouse-set-point event)
|
||||
(thing-at-point 'symbol)))))
|
||||
(unless query
|
||||
(user-error "Nothing to search for"))
|
||||
(browse-url (concat
|
||||
eww-search-prefix
|
||||
(mapconcat #'url-hexify-string (split-string query) "+")))))
|
||||
|
||||
|
||||
;;; Bindings for mouse commands.
|
||||
|
||||
|
@ -1376,7 +1376,7 @@ any buffer where (dictionary-tooltip-mode 1) has been called."
|
||||
(dictionary-search word)))
|
||||
|
||||
;;;###autoload
|
||||
(defun context-menu-dictionary (menu click)
|
||||
(defun dictionary-context-menu (menu click)
|
||||
"Populate MENU with dictionary commands at CLICK.
|
||||
When you add this function to `context-menu-functions',
|
||||
the context menu will contain an item that searches
|
||||
|
@ -319,8 +319,9 @@ attribute name (viewer, test, etc). This looks like:
|
||||
|
||||
Where VIEWERINFO specifies how the content-type is viewed. Can be
|
||||
a string, in which case it is run through a shell, with appropriate
|
||||
parameters, or a symbol, in which case the symbol is `funcall'ed if
|
||||
and only if it exists as a function, with the buffer as an argument.
|
||||
parameters, or a symbol, in which case the symbol must name a function
|
||||
of zero arguments which is called in a buffer holding the MIME part's
|
||||
content.
|
||||
|
||||
TESTINFO is a test for the viewer's applicability, or nil. If nil, it
|
||||
means the viewer is always valid. If it is a Lisp function, it is
|
||||
@ -1175,34 +1176,45 @@ See \"~/.mailcap\", `mailcap-mime-data' and related files and variables."
|
||||
(mailcap-parse-mailcaps)
|
||||
(let ((command (mailcap-mime-info
|
||||
(mailcap-extension-to-mime (file-name-extension file)))))
|
||||
(unless command
|
||||
(error "No viewer for %s" (file-name-extension file)))
|
||||
;; Remove quotes around the file name - we'll use shell-quote-argument.
|
||||
(while (string-match "['\"]%s['\"]" command)
|
||||
(setq command (replace-match "%s" t t command)))
|
||||
(setq command (replace-regexp-in-string
|
||||
"%s"
|
||||
(shell-quote-argument (convert-standard-filename file))
|
||||
command
|
||||
nil t))
|
||||
;; Handlers such as "gio open" and kde-open5 start viewer in background
|
||||
;; and exit immediately. Avoid `start-process' since it assumes
|
||||
;; :connection-type `pty' and kills children processes with SIGHUP
|
||||
;; when temporary terminal session is finished (Bug#44824).
|
||||
;; An alternative is `process-connection-type' let-bound to nil for
|
||||
;; `start-process-shell-command' call (with no chance to report failure).
|
||||
(make-process
|
||||
:name "mailcap-view-file"
|
||||
:connection-type 'pipe
|
||||
:buffer nil ; "*Messages*" may be suitable for debugging
|
||||
:sentinel (lambda (proc event)
|
||||
(when (and (memq (process-status proc) '(exit signal))
|
||||
(/= (process-exit-status proc) 0))
|
||||
(message
|
||||
"Command %s: %s."
|
||||
(mapconcat #'identity (process-command proc) " ")
|
||||
(substring event 0 -1))))
|
||||
:command (list shell-file-name shell-command-switch command))))
|
||||
(if (functionp command)
|
||||
;; command is a viewer function (a mode) expecting the file
|
||||
;; contents to be in the current buffer.
|
||||
(let ((buf (generate-new-buffer (file-name-nondirectory file))))
|
||||
(set-buffer buf)
|
||||
(insert-file-contents file)
|
||||
(setq buffer-file-name file)
|
||||
(funcall command)
|
||||
(set-buffer-modified-p nil)
|
||||
(pop-to-buffer buf))
|
||||
;; command is a program to run with file as an argument.
|
||||
(unless command
|
||||
(error "No viewer for %s" (file-name-extension file)))
|
||||
;; Remove quotes around the file name - we'll use shell-quote-argument.
|
||||
(while (string-match "['\"]%s['\"]" command)
|
||||
(setq command (replace-match "%s" t t command)))
|
||||
(setq command (replace-regexp-in-string
|
||||
"%s"
|
||||
(shell-quote-argument (convert-standard-filename file))
|
||||
command
|
||||
nil t))
|
||||
;; Handlers such as "gio open" and kde-open5 start viewer in background
|
||||
;; and exit immediately. Avoid `start-process' since it assumes
|
||||
;; :connection-type `pty' and kills children processes with SIGHUP
|
||||
;; when temporary terminal session is finished (Bug#44824).
|
||||
;; An alternative is `process-connection-type' let-bound to nil for
|
||||
;; `start-process-shell-command' call (with no chance to report failure).
|
||||
(make-process
|
||||
:name "mailcap-view-file"
|
||||
:connection-type 'pipe
|
||||
:buffer nil ; "*Messages*" may be suitable for debugging
|
||||
:sentinel (lambda (proc event)
|
||||
(when (and (memq (process-status proc) '(exit signal))
|
||||
(/= (process-exit-status proc) 0))
|
||||
(message
|
||||
"Command %s: %s."
|
||||
(mapconcat #'identity (process-command proc) " ")
|
||||
(substring event 0 -1))))
|
||||
:command (list shell-file-name shell-command-switch command)))))
|
||||
|
||||
(provide 'mailcap)
|
||||
|
||||
|
@ -1467,7 +1467,18 @@ ones, in case fg and bg are nil."
|
||||
(dom-attr dom 'name)))) ; Obsolete since HTML5.
|
||||
(push (cons id (point)) shr--link-targets))
|
||||
(when url
|
||||
(shr-urlify (or shr-start start) (shr-expand-url url) title))))
|
||||
(shr-urlify (or shr-start start) (shr-expand-url url) title)
|
||||
;; Check whether the URL is suspicious.
|
||||
(when-let ((warning (or (textsec-suspicious-p
|
||||
(shr-expand-url url) 'url)
|
||||
(textsec-suspicious-p
|
||||
(cons (shr-expand-url url)
|
||||
(buffer-substring (or shr-start start)
|
||||
(point)))
|
||||
'link))))
|
||||
(add-text-properties (or shr-start start) (point)
|
||||
(list 'face '(shr-link textsec-suspicious)))
|
||||
(insert (propertize "⚠️" 'help-echo warning))))))
|
||||
|
||||
(defun shr-tag-abbr (dom)
|
||||
(let ((title (dom-attr dom 'title))
|
||||
|
@ -776,7 +776,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
|
||||
(defun tramp-adb-get-signal-strings (vec)
|
||||
"Strings to return by `process-file' in case of signals."
|
||||
(with-tramp-connection-property vec "signal-strings"
|
||||
(let ((default-directory (tramp-make-tramp-file-name vec 'localname))
|
||||
(let ((default-directory (tramp-make-tramp-file-name vec 'noloc))
|
||||
;; `shell-file-name' and `shell-command-switch' are needed
|
||||
;; for Emacs < 27.1, which doesn't support connection-local
|
||||
;; variables in `shell-command'.
|
||||
@ -815,7 +815,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
|
||||
;; Determine input.
|
||||
(if (null infile)
|
||||
(setq input (tramp-get-remote-null-device v))
|
||||
(setq infile (expand-file-name infile))
|
||||
(setq infile (tramp-compat-file-name-unquote (expand-file-name infile)))
|
||||
(if (tramp-equal-remote default-directory infile)
|
||||
;; INFILE is on the same remote host.
|
||||
(setq input (tramp-file-local-name infile))
|
||||
@ -870,7 +870,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
|
||||
(setq ret (tramp-adb-send-command-and-check
|
||||
v (format
|
||||
"(cd %s; %s)"
|
||||
(tramp-shell-quote-argument localname) command)
|
||||
(tramp-unquote-shell-quote-argument localname)
|
||||
command)
|
||||
t))
|
||||
(unless (natnump ret) (setq ret 1))
|
||||
;; We should add the output anyway.
|
||||
@ -900,8 +901,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
|
||||
;; Cleanup. We remove all file cache values for the connection,
|
||||
;; because the remote process could have changed them.
|
||||
(when tmpinput (delete-file tmpinput))
|
||||
|
||||
(unless process-file-side-effects
|
||||
(when process-file-side-effects
|
||||
(tramp-flush-directory-properties v ""))
|
||||
|
||||
;; Return exit status.
|
||||
|
@ -457,7 +457,7 @@ name is kept in slot `hop'"
|
||||
((tramp-archive-file-name-p archive)
|
||||
(let ((archive
|
||||
(tramp-make-tramp-file-name
|
||||
(tramp-archive-dissect-file-name archive) nil 'noarchive)))
|
||||
(tramp-archive-dissect-file-name archive))))
|
||||
(setf (tramp-file-name-host vec) (tramp-archive-gvfs-host archive)))
|
||||
(puthash archive (list vec) tramp-archive-hash))
|
||||
|
||||
@ -560,8 +560,7 @@ offered."
|
||||
|
||||
(defun tramp-archive-gvfs-file-name (name)
|
||||
"Return NAME in GVFS syntax."
|
||||
(tramp-make-tramp-file-name
|
||||
(tramp-archive-dissect-file-name name) nil 'nohop))
|
||||
(tramp-make-tramp-file-name (tramp-archive-dissect-file-name name)))
|
||||
|
||||
|
||||
;; File name primitives.
|
||||
|
@ -124,7 +124,7 @@ If KEY is `tramp-cache-undefined', don't create anything, and return nil."
|
||||
(dolist (elt tramp-connection-properties)
|
||||
(when (tramp-compat-string-search
|
||||
(or (nth 0 elt) "")
|
||||
(tramp-make-tramp-file-name key 'noloc 'nohop))
|
||||
(tramp-make-tramp-file-name key 'noloc))
|
||||
(tramp-set-connection-property key (nth 1 elt) (nth 2 elt)))))
|
||||
hash))))
|
||||
|
||||
|
@ -1149,8 +1149,7 @@ component is used as the target of the symlink."
|
||||
(when (file-remote-p result)
|
||||
(setq result (tramp-compat-file-name-quote result 'top)))
|
||||
(tramp-message v 4 "True name of `%s' is `%s'" localname result)
|
||||
result))
|
||||
'nohop)))))
|
||||
result)))))))
|
||||
|
||||
;; Basic functions.
|
||||
|
||||
@ -2852,7 +2851,7 @@ implementation will be used."
|
||||
;; `shell'. We discard hops, if existing, that's why
|
||||
;; we cannot use `file-remote-p'.
|
||||
(prompt (format "PS1=%s %s"
|
||||
(tramp-make-tramp-file-name v nil 'nohop)
|
||||
(tramp-make-tramp-file-name v)
|
||||
tramp-initial-end-of-output))
|
||||
;; We use as environment the difference to toplevel
|
||||
;; `process-environment'.
|
||||
@ -3013,7 +3012,7 @@ implementation will be used."
|
||||
vec
|
||||
(concat
|
||||
"signal-strings-" (tramp-get-method-parameter vec 'tramp-remote-shell))
|
||||
(let ((default-directory (tramp-make-tramp-file-name vec 'localname))
|
||||
(let ((default-directory (tramp-make-tramp-file-name vec 'noloc))
|
||||
process-file-return-signal-string signals res result)
|
||||
(setq signals
|
||||
(append
|
||||
@ -3098,13 +3097,13 @@ implementation will be used."
|
||||
;; Determine input.
|
||||
(if (null infile)
|
||||
(setq input (tramp-get-remote-null-device v))
|
||||
(setq infile (expand-file-name infile))
|
||||
(setq infile (tramp-compat-file-name-unquote (expand-file-name infile)))
|
||||
(if (tramp-equal-remote default-directory infile)
|
||||
;; INFILE is on the same remote host.
|
||||
(setq input (tramp-file-local-name infile))
|
||||
;; INFILE must be copied to remote host.
|
||||
(setq input (tramp-make-tramp-temp-file v)
|
||||
tmpinput (tramp-make-tramp-file-name v input 'nohop))
|
||||
tmpinput (tramp-make-tramp-file-name v input))
|
||||
(copy-file infile tmpinput t)))
|
||||
(when input (setq command (format "%s <%s" command input)))
|
||||
|
||||
@ -3136,7 +3135,7 @@ implementation will be used."
|
||||
;; stderr must be copied to remote host. The temporary
|
||||
;; file must be deleted after execution.
|
||||
(setq stderr (tramp-make-tramp-temp-file v)
|
||||
tmpstderr (tramp-make-tramp-file-name v stderr 'nohop))))
|
||||
tmpstderr (tramp-make-tramp-file-name v stderr))))
|
||||
;; stderr to be discarded.
|
||||
((null (cadr destination))
|
||||
(setq stderr (tramp-get-remote-null-device v)))))
|
||||
@ -3153,7 +3152,8 @@ implementation will be used."
|
||||
(setq ret (tramp-send-command-and-check
|
||||
v (format
|
||||
"cd %s && %s"
|
||||
(tramp-shell-quote-argument localname) command)
|
||||
(tramp-unquote-shell-quote-argument localname)
|
||||
command)
|
||||
t t t))
|
||||
(unless (natnump ret) (setq ret 1))
|
||||
;; We should add the output anyway.
|
||||
@ -3184,8 +3184,7 @@ implementation will be used."
|
||||
;; Cleanup. We remove all file cache values for the connection,
|
||||
;; because the remote process could have changed them.
|
||||
(when tmpinput (delete-file tmpinput))
|
||||
|
||||
(unless process-file-side-effects
|
||||
(when process-file-side-effects
|
||||
(tramp-flush-directory-properties v ""))
|
||||
|
||||
;; Return exit status.
|
||||
@ -3650,8 +3649,7 @@ Fall back to normal file name handler if no Tramp handler exists."
|
||||
(defun tramp-sh-file-name-handler-p (vec)
|
||||
"Whether VEC uses a method from `tramp-sh-file-name-handler'."
|
||||
(and (assoc (tramp-file-name-method vec) tramp-methods)
|
||||
(eq (tramp-find-foreign-file-name-handler
|
||||
(tramp-make-tramp-file-name vec nil 'nohop))
|
||||
(eq (tramp-find-foreign-file-name-handler vec)
|
||||
'tramp-sh-file-name-handler)))
|
||||
|
||||
;; This must be the last entry, because `identity' always matches.
|
||||
@ -5441,7 +5439,7 @@ Nonexistent directories are removed from spec."
|
||||
(lambda (x)
|
||||
(and
|
||||
(stringp x)
|
||||
(file-directory-p (tramp-make-tramp-file-name vec x 'nohop))
|
||||
(file-directory-p (tramp-make-tramp-file-name vec x))
|
||||
x))
|
||||
remote-path))))))
|
||||
|
||||
|
@ -1281,7 +1281,7 @@ component is used as the target of the symlink."
|
||||
|
||||
;; Determine input.
|
||||
(when infile
|
||||
(setq infile (expand-file-name infile))
|
||||
(setq infile (tramp-compat-file-name-unquote (expand-file-name infile)))
|
||||
(if (tramp-equal-remote default-directory infile)
|
||||
;; INFILE is on the same remote host.
|
||||
(setq input (tramp-file-local-name infile))
|
||||
@ -1373,8 +1373,7 @@ component is used as the target of the symlink."
|
||||
(when tmpinput (delete-file tmpinput))
|
||||
(unless outbuf
|
||||
(kill-buffer (tramp-get-connection-property v "process-buffer" nil)))
|
||||
|
||||
(unless process-file-side-effects
|
||||
(when process-file-side-effects
|
||||
(tramp-flush-directory-properties v ""))
|
||||
|
||||
;; Return exit status.
|
||||
|
@ -137,7 +137,7 @@
|
||||
(set-file-acl . ignore)
|
||||
(set-file-modes . tramp-sshfs-handle-set-file-modes)
|
||||
(set-file-selinux-context . ignore)
|
||||
(set-file-times . ignore)
|
||||
(set-file-times . tramp-sshfs-handle-set-file-times)
|
||||
(set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
|
||||
(shell-command . tramp-handle-shell-command)
|
||||
(start-file-process . tramp-handle-start-file-process)
|
||||
@ -242,13 +242,28 @@ arguments to pass to the OPERATION."
|
||||
(let ((command
|
||||
(format
|
||||
"cd %s && exec %s"
|
||||
localname
|
||||
(mapconcat #'tramp-shell-quote-argument (cons program args) " "))))
|
||||
(tramp-unquote-shell-quote-argument localname)
|
||||
(mapconcat #'tramp-shell-quote-argument (cons program args) " ")))
|
||||
input tmpinput)
|
||||
|
||||
;; Determine input.
|
||||
(if (null infile)
|
||||
(setq input (tramp-get-remote-null-device v))
|
||||
(setq infile (tramp-compat-file-name-unquote (expand-file-name infile)))
|
||||
(if (tramp-equal-remote default-directory infile)
|
||||
;; INFILE is on the same remote host.
|
||||
(setq input (tramp-file-local-name infile))
|
||||
;; INFILE must be copied to remote host.
|
||||
(setq input (tramp-make-tramp-temp-file v)
|
||||
tmpinput (tramp-make-tramp-file-name v input))
|
||||
(copy-file infile tmpinput t)))
|
||||
(when input (setq command (format "%s <%s" command input)))
|
||||
|
||||
(unwind-protect
|
||||
(apply
|
||||
#'tramp-call-process
|
||||
v (tramp-get-method-parameter v 'tramp-login-program)
|
||||
infile destination display
|
||||
nil destination display
|
||||
(tramp-expand-args
|
||||
v 'tramp-login-args
|
||||
?h (or (tramp-file-name-host v) "")
|
||||
@ -256,7 +271,11 @@ arguments to pass to the OPERATION."
|
||||
?p (or (tramp-file-name-port v) "")
|
||||
?l command))
|
||||
|
||||
(unless process-file-side-effects
|
||||
;; Cleanup. We remove all file cache values for the
|
||||
;; connection, because the remote process could have changed
|
||||
;; them.
|
||||
(when tmpinput (delete-file tmpinput))
|
||||
(when process-file-side-effects
|
||||
(tramp-flush-directory-properties v ""))))))
|
||||
|
||||
(defun tramp-sshfs-handle-rename-file
|
||||
@ -285,6 +304,15 @@ arguments to pass to the OPERATION."
|
||||
(tramp-compat-set-file-modes
|
||||
(tramp-fuse-local-file-name filename) mode flag))))
|
||||
|
||||
(defun tramp-sshfs-handle-set-file-times (filename &optional timestamp flag)
|
||||
"Like `set-file-times' for Tramp files."
|
||||
(or (file-exists-p filename) (write-region "" nil filename nil 0))
|
||||
(with-parsed-tramp-file-name filename nil
|
||||
(unless (and (eq flag 'nofollow) (file-symlink-p filename))
|
||||
(tramp-flush-file-properties v localname)
|
||||
(tramp-compat-set-file-times
|
||||
(tramp-fuse-local-file-name filename) timestamp flag))))
|
||||
|
||||
(defun tramp-sshfs-handle-write-region
|
||||
(start end filename &optional append visit lockname mustbenew)
|
||||
"Like `write-region' for Tramp files."
|
||||
|
@ -572,8 +572,7 @@ the result will be a local, non-Tramp, file name."
|
||||
(when (file-remote-p result)
|
||||
(setq result (tramp-compat-file-name-quote result 'top)))
|
||||
(tramp-message v 4 "True name of `%s' is `%s'" localname result)
|
||||
result))
|
||||
'nohop)))))
|
||||
result)))))))
|
||||
|
||||
(defun tramp-sudoedit-handle-file-writable-p (filename)
|
||||
"Like `file-writable-p' for Tramp files."
|
||||
|
@ -1713,13 +1713,10 @@ See `tramp-dissect-file-name' for details."
|
||||
"Construct a Tramp file name from ARGS.
|
||||
|
||||
ARGS could have two different signatures. The first one is of
|
||||
type (VEC &optional LOCALNAME HOP).
|
||||
type (VEC &optional LOCALNAME).
|
||||
If LOCALNAME is nil, the value in VEC is used. If it is a
|
||||
symbol, a null localname will be used. Otherwise, LOCALNAME is
|
||||
expected to be a string, which will be used.
|
||||
If HOP is nil, the value in VEC is used. If it is a symbol, a
|
||||
null hop will be used. Otherwise, HOP is expected to be a
|
||||
string, which will be used.
|
||||
|
||||
The other signature exists for backward compatibility. It has
|
||||
the form (METHOD USER DOMAIN HOST PORT LOCALNAME &optional HOP)."
|
||||
@ -1735,8 +1732,13 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME &optional HOP)."
|
||||
hop (tramp-file-name-hop (car args)))
|
||||
(when (cadr args)
|
||||
(setq localname (and (stringp (cadr args)) (cadr args))))
|
||||
(when (cl-caddr args)
|
||||
(setq hop (and (stringp (cl-caddr args)) (cl-caddr args)))))
|
||||
(when hop
|
||||
(setq hop nil)
|
||||
;; Assure that the hops are in `tramp-default-proxies-alist'.
|
||||
;; In tramp-archive.el, the slot `hop' is used for the archive
|
||||
;; file name.
|
||||
(unless (string-equal method "archive")
|
||||
(tramp-add-hops (car args)))))
|
||||
|
||||
(t (setq method (nth 0 args)
|
||||
user (nth 1 args)
|
||||
@ -1769,15 +1771,17 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME &optional HOP)."
|
||||
localname)))
|
||||
|
||||
(set-advertised-calling-convention
|
||||
#'tramp-make-tramp-file-name '(vec &optional localname hop) "27.1")
|
||||
#'tramp-make-tramp-file-name '(vec &optional localname) "29.1")
|
||||
|
||||
(defun tramp-make-tramp-hop-name (vec)
|
||||
"Construct a Tramp hop name from VEC."
|
||||
(replace-regexp-in-string
|
||||
tramp-prefix-regexp ""
|
||||
(concat
|
||||
(tramp-file-name-hop vec)
|
||||
(replace-regexp-in-string
|
||||
(concat tramp-postfix-host-regexp "$") tramp-postfix-hop-format
|
||||
(tramp-make-tramp-file-name vec 'noloc))))
|
||||
tramp-prefix-regexp ""
|
||||
(replace-regexp-in-string
|
||||
(concat tramp-postfix-host-regexp "$") tramp-postfix-hop-format
|
||||
(tramp-make-tramp-file-name vec 'noloc)))))
|
||||
|
||||
(defun tramp-completion-make-tramp-file-name (method user host localname)
|
||||
"Construct a Tramp file name from METHOD, USER, HOST and LOCALNAME.
|
||||
@ -1811,7 +1815,7 @@ Unless DONT-CREATE, the buffer is created when it doesn't exist yet."
|
||||
(tramp-get-connection-property vec "process-buffer" nil))
|
||||
(setq buffer-undo-list t
|
||||
default-directory
|
||||
(tramp-make-tramp-file-name vec 'noloc 'nohop))
|
||||
(tramp-make-tramp-file-name vec 'noloc))
|
||||
(current-buffer)))))
|
||||
|
||||
(defun tramp-get-connection-buffer (vec &optional dont-create)
|
||||
@ -1926,7 +1930,7 @@ The outline level is equal to the verbosity of the Tramp message."
|
||||
"A predicate for Tramp interactive commands.
|
||||
They are completed by \"M-x TAB\" only in Tramp debug buffers."
|
||||
(with-current-buffer buffer
|
||||
(string-equal (buffer-substring 1 10) ";; Emacs:")))
|
||||
(string-equal (buffer-substring 1 (min 10 (point-max))) ";; Emacs:")))
|
||||
|
||||
(put #'tramp-debug-buffer-command-completion-p 'tramp-suppress-trace t)
|
||||
|
||||
@ -2596,11 +2600,10 @@ Must be handled by the callers."
|
||||
;; Unknown file primitive.
|
||||
(t (error "Unknown file I/O primitive: %s" operation))))
|
||||
|
||||
(defun tramp-find-foreign-file-name-handler (filename &optional _operation)
|
||||
(defun tramp-find-foreign-file-name-handler (vec &optional _operation)
|
||||
"Return foreign file name handler if exists."
|
||||
(when (tramp-tramp-file-p filename)
|
||||
(when (tramp-file-name-p vec)
|
||||
(let ((handler tramp-foreign-file-name-handler-alist)
|
||||
(vec (tramp-dissect-file-name filename))
|
||||
elt func res)
|
||||
(while handler
|
||||
(setq elt (car handler)
|
||||
@ -2633,7 +2636,7 @@ Fall back to normal file name handler if no Tramp file name handler exists."
|
||||
(with-parsed-tramp-file-name filename nil
|
||||
(let ((current-connection tramp-current-connection)
|
||||
(foreign
|
||||
(tramp-find-foreign-file-name-handler filename operation))
|
||||
(tramp-find-foreign-file-name-handler v operation))
|
||||
(signal-hook-function #'tramp-signal-hook-function)
|
||||
result)
|
||||
;; Set `tramp-current-connection'.
|
||||
@ -3351,7 +3354,7 @@ User is always nil."
|
||||
(tramp-compat-funcall 'directory-abbrev-make-regexp home-dir) filename)
|
||||
(tramp-make-tramp-file-name
|
||||
vec (concat "~" (substring filename (match-beginning 1))))
|
||||
filename)))
|
||||
(tramp-make-tramp-file-name (tramp-dissect-file-name filename)))))
|
||||
|
||||
(defun tramp-handle-access-file (filename string)
|
||||
"Like `access-file' for Tramp files."
|
||||
@ -3678,8 +3681,8 @@ User is always nil."
|
||||
;; We do not want traces in the debug buffer.
|
||||
(let ((tramp-verbose (min tramp-verbose 3)))
|
||||
(when (tramp-tramp-file-p filename)
|
||||
(let* ((v (tramp-dissect-file-name filename))
|
||||
(p (tramp-get-connection-process v))
|
||||
(let* ((o (tramp-dissect-file-name filename))
|
||||
(p (tramp-get-connection-process o))
|
||||
(c (and (process-live-p p)
|
||||
(tramp-get-connection-property p "connected" nil))))
|
||||
;; We expand the file name only, if there is already a connection.
|
||||
@ -3693,7 +3696,8 @@ User is always nil."
|
||||
((eq identification 'user) (tramp-file-name-user-domain v))
|
||||
((eq identification 'host) (tramp-file-name-host-port v))
|
||||
((eq identification 'localname) localname)
|
||||
((eq identification 'hop) hop)
|
||||
;; Hop exists only in original dissected file name.
|
||||
((eq identification 'hop) (tramp-file-name-hop o))
|
||||
(t (tramp-make-tramp-file-name v 'noloc)))))))))
|
||||
|
||||
(defun tramp-handle-file-selinux-context (_filename)
|
||||
@ -3744,8 +3748,7 @@ User is always nil."
|
||||
(expand-file-name
|
||||
symlink-target
|
||||
(file-name-directory v2-localname))))
|
||||
v2-localname)
|
||||
'nohop)))
|
||||
v2-localname))))
|
||||
(when (>= numchase numchase-limit)
|
||||
(tramp-error
|
||||
v1 'file-error
|
||||
@ -3904,8 +3907,7 @@ User is always nil."
|
||||
(cond
|
||||
((stringp remote-copy)
|
||||
(file-local-copy
|
||||
(tramp-make-tramp-file-name
|
||||
v remote-copy 'nohop)))
|
||||
(tramp-make-tramp-file-name v remote-copy)))
|
||||
((stringp tramp-temp-buffer-file-name)
|
||||
(copy-file
|
||||
filename tramp-temp-buffer-file-name 'ok)
|
||||
@ -3948,7 +3950,7 @@ User is always nil."
|
||||
(or remote-copy (null tramp-temp-buffer-file-name)))
|
||||
(delete-file local-copy))
|
||||
(when (stringp remote-copy)
|
||||
(delete-file (tramp-make-tramp-file-name v remote-copy 'nohop))))
|
||||
(delete-file (tramp-make-tramp-file-name v remote-copy))))
|
||||
|
||||
;; Result.
|
||||
(cons filename (cdr result)))))
|
||||
@ -4088,15 +4090,10 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.")
|
||||
(and (tramp-sh-file-name-handler-p vec)
|
||||
(not (tramp-get-method-parameter vec 'tramp-copy-program))))
|
||||
|
||||
(defun tramp-compute-multi-hops (vec)
|
||||
"Expands VEC according to `tramp-default-proxies-alist'."
|
||||
(let ((saved-tdpa tramp-default-proxies-alist)
|
||||
(target-alist `(,vec))
|
||||
(hops (or (tramp-file-name-hop vec) ""))
|
||||
(item vec)
|
||||
choices proxy)
|
||||
|
||||
;; Ad-hoc proxy definitions.
|
||||
(defun tramp-add-hops (vec)
|
||||
"Add ad-hoc proxy definitions to `tramp-default-proxies-alist'."
|
||||
(when-let ((hops (tramp-file-name-hop vec))
|
||||
(item vec))
|
||||
(dolist (proxy (reverse (split-string hops tramp-postfix-hop-regexp 'omit)))
|
||||
(let* ((host-port (tramp-file-name-host-port item))
|
||||
(user-domain (tramp-file-name-user-domain item))
|
||||
@ -4113,9 +4110,19 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.")
|
||||
(add-to-list 'tramp-default-proxies-alist entry)
|
||||
(setq item (tramp-dissect-file-name proxy))))
|
||||
;; Save the new value.
|
||||
(when (and hops tramp-save-ad-hoc-proxies)
|
||||
(when tramp-save-ad-hoc-proxies
|
||||
(customize-save-variable
|
||||
'tramp-default-proxies-alist tramp-default-proxies-alist))
|
||||
'tramp-default-proxies-alist tramp-default-proxies-alist))))
|
||||
|
||||
(defun tramp-compute-multi-hops (vec)
|
||||
"Expands VEC according to `tramp-default-proxies-alist'."
|
||||
(let ((saved-tdpa tramp-default-proxies-alist)
|
||||
(target-alist `(,vec))
|
||||
(item vec)
|
||||
choices proxy)
|
||||
|
||||
;; Ad-hoc proxy definitions.
|
||||
(tramp-add-hops vec)
|
||||
|
||||
;; Look for proxy hosts to be passed.
|
||||
(setq choices tramp-default-proxies-alist)
|
||||
@ -5462,8 +5469,7 @@ This handles also chrooted environments, which are not regarded as local."
|
||||
(null tramp-crypt-enabled)
|
||||
;; The local temp directory must be writable for the other user.
|
||||
(file-writable-p
|
||||
(tramp-make-tramp-file-name
|
||||
vec tramp-compat-temporary-file-directory 'nohop))
|
||||
(tramp-make-tramp-file-name vec tramp-compat-temporary-file-directory))
|
||||
;; On some systems, chown runs only for root.
|
||||
(or (zerop (user-uid))
|
||||
(zerop (tramp-get-remote-uid vec 'integer))))))
|
||||
@ -5712,7 +5718,7 @@ Invokes `password-read' if available, `read-passwd' else."
|
||||
;; multi-hop.
|
||||
(tramp-get-connection-property
|
||||
proc "password-vector" (process-get proc 'vector))
|
||||
'noloc 'nohop))
|
||||
'noloc))
|
||||
(pw-prompt
|
||||
(or prompt
|
||||
(with-current-buffer (process-buffer proc)
|
||||
@ -5789,7 +5795,7 @@ Invokes `password-read' if available, `read-passwd' else."
|
||||
(auth-source-forget
|
||||
`(:max 1 ,(and user-domain :user) ,user-domain
|
||||
:host ,host-port :port ,method))
|
||||
(password-cache-remove (tramp-make-tramp-file-name vec 'noloc 'nohop))))
|
||||
(password-cache-remove (tramp-make-tramp-file-name vec 'noloc))))
|
||||
|
||||
(put #'tramp-clear-passwd 'tramp-suppress-trace t)
|
||||
|
||||
|
@ -129,6 +129,7 @@ code."
|
||||
(title (cdr (assq :title params)))
|
||||
(lines (cdr (assq :line params)))
|
||||
(sets (cdr (assq :set params)))
|
||||
(missing (cdr (assq :missing params)))
|
||||
(x-labels (cdr (assq :xlabels params)))
|
||||
(y-labels (cdr (assq :ylabels params)))
|
||||
(timefmt (cdr (assq :timefmt params)))
|
||||
@ -138,6 +139,7 @@ code."
|
||||
(file-name-directory (buffer-file-name))))
|
||||
(add-to-body (lambda (text) (setq body (concat text "\n" body)))))
|
||||
;; append header argument settings to body
|
||||
(when missing (funcall add-to-body (format "set datafile missing '%s'" missing)))
|
||||
(when title (funcall add-to-body (format "set title '%s'" title)))
|
||||
(when lines (mapc (lambda (el) (funcall add-to-body el)) lines))
|
||||
(when sets
|
||||
@ -288,21 +290,14 @@ Pass PARAMS through to `orgtbl-to-generic' when exporting TABLE."
|
||||
(with-temp-file data-file
|
||||
(insert (let ((org-babel-gnuplot-timestamp-fmt
|
||||
(or (plist-get params :timefmt) "%Y-%m-%d-%H:%M:%S")))
|
||||
(replace-regexp-in-string
|
||||
;; org export backend adds "|" at the beginning/end of
|
||||
;; the table lines. Strip those.
|
||||
"^|\\(.+\\)|$"
|
||||
"\\1"
|
||||
(orgtbl-to-generic
|
||||
table
|
||||
(org-combine-plists
|
||||
'( :sep "\t" :fmt org-babel-gnuplot-quote-tsv-field
|
||||
;; Two setting below are needed to make :fmt work.
|
||||
:raw t
|
||||
;; Use `org', not `ascii' because `ascii' may
|
||||
;; sometimes mishandle quoted strings.
|
||||
:backend org)
|
||||
params))))))
|
||||
(orgtbl-to-generic
|
||||
table
|
||||
(org-combine-plists
|
||||
'( :sep "\t" :fmt org-babel-gnuplot-quote-tsv-field
|
||||
;; Two setting below are needed to make :fmt work.
|
||||
:raw t
|
||||
:backend ascii)
|
||||
params)))))
|
||||
data-file)
|
||||
|
||||
(provide 'ob-gnuplot)
|
||||
|
@ -86,6 +86,8 @@
|
||||
(declare-function org-capture "org-capture" (&optional goto keys))
|
||||
(declare-function org-clock-modify-effort-estimate "org-clock" (&optional value))
|
||||
|
||||
(declare-function org-element-type "org-element" (&optional element))
|
||||
|
||||
(defvar calendar-mode-map)
|
||||
(defvar org-clock-current-task)
|
||||
(defvar org-current-tag-alist)
|
||||
@ -5729,7 +5731,8 @@ displayed in agenda view."
|
||||
(org-at-planning-p)
|
||||
(org-before-first-heading-p)
|
||||
(and org-agenda-include-inactive-timestamps
|
||||
(org-at-clock-log-p)))
|
||||
(org-at-clock-log-p))
|
||||
(not (eq 'timestamp (org-element-type (org-element-context)))))
|
||||
(throw :skip nil))
|
||||
(org-agenda-skip))
|
||||
(let* ((pos (match-beginning 0))
|
||||
|
@ -11,7 +11,7 @@ Inserted by installing Org mode or when a release is made."
|
||||
(defun org-git-version ()
|
||||
"The Git version of Org mode.
|
||||
Inserted by installing Org or when a release is made."
|
||||
(let ((org-git-version "release_9.5.2-3-geb9f34"))
|
||||
(let ((org-git-version "release_9.5.2-9-g7ba24c"))
|
||||
org-git-version))
|
||||
|
||||
(provide 'org-version)
|
||||
|
@ -18731,17 +18731,19 @@ With prefix arg UNCOMPILED, load the uncompiled versions."
|
||||
"Is S an ID created by UUIDGEN?"
|
||||
(string-match "\\`[0-9a-f]\\{8\\}-[0-9a-f]\\{4\\}-[0-9a-f]\\{4\\}-[0-9a-f]\\{4\\}-[0-9a-f]\\{12\\}\\'" (downcase s)))
|
||||
|
||||
(defun org-in-src-block-p (&optional inside)
|
||||
(defun org-in-src-block-p (&optional inside element)
|
||||
"Whether point is in a code source block.
|
||||
When INSIDE is non-nil, don't consider we are within a source
|
||||
block when point is at #+BEGIN_SRC or #+END_SRC."
|
||||
(let ((case-fold-search t))
|
||||
(or (and (eq (get-char-property (point) 'src-block) t))
|
||||
(and (not inside)
|
||||
(save-match-data
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(looking-at ".*#\\+\\(begin\\|end\\)_src")))))))
|
||||
block when point is at #+BEGIN_SRC or #+END_SRC.
|
||||
When ELEMENT is provided, it is considered to be element at point."
|
||||
(save-match-data (setq element (or element (org-element-at-point))))
|
||||
(when (eq 'src-block (org-element-type element))
|
||||
(or (not inside)
|
||||
(not (or (= (line-beginning-position)
|
||||
(org-element-property :post-affiliated element))
|
||||
(= (1+ (line-end-position))
|
||||
(- (org-element-property :end element)
|
||||
(org-element-property :post-blank element))))))))
|
||||
|
||||
(defun org-context ()
|
||||
"Return a list of contexts of the current cursor position.
|
||||
|
@ -1929,7 +1929,11 @@ a communication channel."
|
||||
(org-export-table-cell-alignment table-cell info)))))
|
||||
(setq contents
|
||||
(concat data
|
||||
(make-string (- width (string-width (or data ""))) ?\s))))
|
||||
;; FIXME: If CONTENTS was transformed by filters,
|
||||
;; the whole width calculation can be wrong.
|
||||
;; At least, make sure that we do not throw error
|
||||
;; when CONTENTS is larger than width.
|
||||
(make-string (max 0 (- width (string-width (or data "")))) ?\s))))
|
||||
;; Return cell.
|
||||
(concat (format " %s " contents)
|
||||
(when (memq 'right (org-export-table-cell-borders table-cell info))
|
||||
|
178
lisp/outline.el
178
lisp/outline.el
@ -351,7 +351,8 @@ Turning on outline mode calls the value of `text-mode-hook' and then of
|
||||
'(outline-font-lock-keywords t nil nil backward-paragraph))
|
||||
(setq-local imenu-generic-expression
|
||||
(list (list nil (concat "^\\(?:" outline-regexp "\\).*$") 0)))
|
||||
(add-hook 'change-major-mode-hook #'outline-show-all nil t))
|
||||
(add-hook 'change-major-mode-hook #'outline-show-all nil t)
|
||||
(add-hook 'hack-local-variables-hook #'outline-apply-default-state nil t))
|
||||
|
||||
(defvar outline-minor-mode-map)
|
||||
|
||||
@ -434,7 +435,8 @@ See the command `outline-mode' for more information on this mode."
|
||||
nil t)
|
||||
(setq-local line-move-ignore-invisible t)
|
||||
;; Cause use of ellipses for invisible text.
|
||||
(add-to-invisibility-spec '(outline . t)))
|
||||
(add-to-invisibility-spec '(outline . t))
|
||||
(outline-apply-default-state))
|
||||
(when outline-minor-mode-highlight
|
||||
(if font-lock-fontified
|
||||
(font-lock-remove-keywords nil outline-font-lock-keywords))
|
||||
@ -1303,6 +1305,178 @@ convenient way to make a table of contents of the buffer."
|
||||
(insert "\n\n"))))))
|
||||
(kill-new (buffer-string)))))))
|
||||
|
||||
(defcustom outline-default-state nil
|
||||
"If non-nil, some headings are initially outlined.
|
||||
|
||||
Note that the default state is applied when the major mode is set
|
||||
or when the command `outline-apply-default-state' is called
|
||||
interactively.
|
||||
|
||||
When nil, headings visibility is left unchanged.
|
||||
|
||||
If equal to `outline-show-all', all text of buffer is shown.
|
||||
|
||||
If equal to `outline-show-only-headings', only headings are shown.
|
||||
|
||||
If equal to a number, show only headings up to and including the
|
||||
corresponding level. See `outline-default-rules' to customize
|
||||
visibility of the subtree at the choosen level.
|
||||
|
||||
If equal to a lambda function or function name, this function is
|
||||
expected to toggle headings visibility, and will be called after
|
||||
the mode is enabled."
|
||||
:version "29.1"
|
||||
:type '(choice (const :tag "Disabled" nil)
|
||||
(const :tag "Show all" outline-show-all)
|
||||
(const :tag "Only headings" outline-show-only-headings)
|
||||
(natnum :tag "Show headings up to level" :value 1)
|
||||
(function :tag "Custom function")))
|
||||
|
||||
(defcustom outline-default-rules nil
|
||||
"Determines visibility of subtree starting at `outline-default-state' level.
|
||||
|
||||
When nil, the subtree is hidden unconditionally.
|
||||
|
||||
When equal to a list, each element should be one of the following:
|
||||
|
||||
- A cons cell with CAR `match-regexp' and CDR a regexp, the
|
||||
subtree will be hidden when the outline heading match the
|
||||
regexp.
|
||||
|
||||
- `subtree-has-long-lines' to only show the heading branches when
|
||||
long lines are detected in its subtree (see
|
||||
`outline-default-long-line' for the definition of long lines).
|
||||
|
||||
- `subtree-is-long' to only show the heading branches when its
|
||||
subtree contains more than `outline-default-line-count' lines.
|
||||
|
||||
- A lambda function or function name which will be evaluated with
|
||||
point at the beginning of the heading and the match data set
|
||||
appropriately, the function being expected to toggle the
|
||||
heading visibility."
|
||||
:version "29.1"
|
||||
:type '(choice (const :tag "Hide subtree" nil)
|
||||
(set :tag "Show subtree unless"
|
||||
(cons :tag "Heading match regexp"
|
||||
(const match-regexp) string)
|
||||
(const :tag "Subtree has long lines"
|
||||
subtree-has-long-lines)
|
||||
(const :tag "Subtree is long"
|
||||
subtree-is-long)
|
||||
(cons :tag "Custom function"
|
||||
(const custom-function) function))))
|
||||
|
||||
(defcustom outline-default-long-line 1000
|
||||
"Minimal number of characters in a line for a heading to be outlined."
|
||||
:version "29.1"
|
||||
:type '(natnum :tag "Number of characters"))
|
||||
|
||||
(defcustom outline-default-line-count 50
|
||||
"Minimal number of lines for a heading to be outlined."
|
||||
:version "29.1"
|
||||
:type '(natnum :tag "Number of lines"))
|
||||
|
||||
(defun outline-apply-default-state ()
|
||||
"Apply the outline state defined by `outline-default-state'."
|
||||
(interactive)
|
||||
(cond
|
||||
((integerp outline-default-state)
|
||||
(outline--show-headings-up-to-level outline-default-state))
|
||||
((functionp outline-default-state)
|
||||
(funcall outline-default-state))))
|
||||
|
||||
(defun outline-show-only-headings ()
|
||||
"Show only headings."
|
||||
(interactive)
|
||||
(outline-show-all)
|
||||
(outline-hide-region-body (point-min) (point-max)))
|
||||
|
||||
(eval-when-compile (require 'so-long))
|
||||
(autoload 'so-long-detected-long-line-p "so-long")
|
||||
(defvar so-long-skip-leading-comments)
|
||||
(defvar so-long-threshold)
|
||||
(defvar so-long-max-lines)
|
||||
|
||||
(defun outline--show-headings-up-to-level (level)
|
||||
"Show only headings up to a LEVEL level.
|
||||
|
||||
Like `outline-hide-sublevels' but, for each heading at level
|
||||
LEVEL, decides of subtree visibility according to
|
||||
`outline-default-rules'."
|
||||
(if (not outline-default-rules)
|
||||
(outline-hide-sublevels level)
|
||||
(if (< level 1)
|
||||
(error "Must keep at least one level of headers"))
|
||||
(save-excursion
|
||||
(let* (outline-view-change-hook
|
||||
(beg (progn
|
||||
(goto-char (point-min))
|
||||
;; Skip the prelude, if any.
|
||||
(unless (outline-on-heading-p t) (outline-next-heading))
|
||||
(point)))
|
||||
(end (progn
|
||||
(goto-char (point-max))
|
||||
;; Keep empty last line, if available.
|
||||
(if (bolp) (1- (point)) (point))))
|
||||
(heading-regexp
|
||||
(cdr-safe
|
||||
(assoc 'match-regexp outline-default-rules)))
|
||||
(check-line-count
|
||||
(memq 'subtree-is-long outline-default-rules))
|
||||
(check-long-lines
|
||||
(memq 'subtree-has-long-lines outline-default-rules))
|
||||
(custom-function
|
||||
(cdr-safe
|
||||
(assoc 'custom-function outline-default-rules))))
|
||||
(if (< end beg)
|
||||
(setq beg (prog1 end (setq end beg))))
|
||||
;; First hide everything.
|
||||
(outline-hide-sublevels level)
|
||||
;; Then unhide the top level headers.
|
||||
(outline-map-region
|
||||
(lambda ()
|
||||
(let ((current-level (funcall outline-level)))
|
||||
(when (< current-level level)
|
||||
(outline-show-heading)
|
||||
(outline-show-entry))
|
||||
(when (= current-level level)
|
||||
(cond
|
||||
((and heading-regexp
|
||||
(let ((beg (point))
|
||||
(end (progn (outline-end-of-heading) (point))))
|
||||
(string-match-p heading-regexp (buffer-substring beg end))))
|
||||
;; hide entry when heading match regexp
|
||||
(outline-hide-entry))
|
||||
((and check-line-count
|
||||
(save-excursion
|
||||
(let ((beg (point))
|
||||
(end (progn (outline-end-of-subtree) (point))))
|
||||
(<= outline-default-line-count (count-lines beg end)))))
|
||||
;; show only branches when line count of subtree >
|
||||
;; threshold
|
||||
(outline-show-branches))
|
||||
((and check-long-lines
|
||||
(save-excursion
|
||||
(let ((beg (point))
|
||||
(end (progn (outline-end-of-subtree) (point))))
|
||||
(save-restriction
|
||||
(narrow-to-region beg end)
|
||||
(let ((so-long-skip-leading-comments nil)
|
||||
(so-long-threshold outline-default-long-line)
|
||||
(so-long-max-lines nil))
|
||||
(so-long-detected-long-line-p))))))
|
||||
;; show only branches when long lines are detected
|
||||
;; in subtree
|
||||
(outline-show-branches))
|
||||
(custom-function
|
||||
;; call custom function if defined
|
||||
(funcall custom-function))
|
||||
(t
|
||||
;; if no previous clause succeeds, show subtree
|
||||
(outline-show-subtree))))))
|
||||
beg end)))
|
||||
(run-hooks 'outline-view-change-hook)))
|
||||
|
||||
(defun outline--cycle-state ()
|
||||
"Return the cycle state of current heading.
|
||||
Return either 'hide-all, 'headings-only, or 'show-all."
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user