From b721ef168f26f66dab4cd455eb15b2223ae5618c Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Sat, 2 Nov 2019 13:52:01 +0100 Subject: [PATCH] add missing dependency packages --- .../julia-latexsubs.el | 3324 +++++++++++++++++ .../julia-mode-autoloads.el | 37 + .../julia-mode-pkg.el | 6 + elpa/julia-mode-20191002.1352/julia-mode.el | 946 +++++ elpa/julia-mode-readme.txt | 1 + .../pcre2el-autoloads.el | 217 ++ elpa/pcre2el-20161120.2103/pcre2el-pkg.el | 2 + elpa/pcre2el-20161120.2103/pcre2el.el | 3157 ++++++++++++++++ elpa/pcre2el-readme.txt | 381 ++ elpa/sesman-20190909.1754/sesman-autoloads.el | 98 + elpa/sesman-20190909.1754/sesman-browser.el | 482 +++ elpa/sesman-20190909.1754/sesman-pkg.el | 12 + elpa/sesman-20190909.1754/sesman.el | 1003 +++++ elpa/sesman-readme.txt | 3 + elpa/xml+-20170727.2351/xml+-autoloads.el | 15 + elpa/xml+-20170727.2351/xml+-pkg.el | 2 + elpa/xml+-20170727.2351/xml+.el | 147 + elpa/xml+-readme.txt | 5 + 18 files changed, 9838 insertions(+) create mode 100644 elpa/julia-mode-20191002.1352/julia-latexsubs.el create mode 100644 elpa/julia-mode-20191002.1352/julia-mode-autoloads.el create mode 100644 elpa/julia-mode-20191002.1352/julia-mode-pkg.el create mode 100644 elpa/julia-mode-20191002.1352/julia-mode.el create mode 100644 elpa/julia-mode-readme.txt create mode 100644 elpa/pcre2el-20161120.2103/pcre2el-autoloads.el create mode 100644 elpa/pcre2el-20161120.2103/pcre2el-pkg.el create mode 100644 elpa/pcre2el-20161120.2103/pcre2el.el create mode 100644 elpa/pcre2el-readme.txt create mode 100644 elpa/sesman-20190909.1754/sesman-autoloads.el create mode 100644 elpa/sesman-20190909.1754/sesman-browser.el create mode 100644 elpa/sesman-20190909.1754/sesman-pkg.el create mode 100644 elpa/sesman-20190909.1754/sesman.el create mode 100644 elpa/sesman-readme.txt create mode 100644 elpa/xml+-20170727.2351/xml+-autoloads.el create mode 100644 elpa/xml+-20170727.2351/xml+-pkg.el create mode 100644 elpa/xml+-20170727.2351/xml+.el create mode 100644 elpa/xml+-readme.txt diff --git a/elpa/julia-mode-20191002.1352/julia-latexsubs.el b/elpa/julia-mode-20191002.1352/julia-latexsubs.el new file mode 100644 index 00000000..6d070808 --- /dev/null +++ b/elpa/julia-mode-20191002.1352/julia-latexsubs.el @@ -0,0 +1,3324 @@ +(puthash "\\exclamdown" "¡" julia-latexsubs) +(puthash "\\sterling" "£" julia-latexsubs) +(puthash "\\yen" "¥" julia-latexsubs) +(puthash "\\brokenbar" "¦" julia-latexsubs) +(puthash "\\S" "§" julia-latexsubs) +(puthash "\\copyright" "©" julia-latexsubs) +(puthash "\\:copyright:" "©" julia-latexsubs) +(puthash "\\ordfeminine" "ª" julia-latexsubs) +(puthash "\\neg" "¬" julia-latexsubs) +(puthash "\\:registered:" "®" julia-latexsubs) +(puthash "\\circledR" "®" julia-latexsubs) +(puthash "\\highminus" "¯" julia-latexsubs) +(puthash "\\degree" "°" julia-latexsubs) +(puthash "\\pm" "±" julia-latexsubs) +(puthash "\\^2" "²" julia-latexsubs) +(puthash "\\^3" "³" julia-latexsubs) +(puthash "\\P" "¶" julia-latexsubs) +(puthash "\\cdotp" "·" julia-latexsubs) +(puthash "\\^1" "¹" julia-latexsubs) +(puthash "\\ordmasculine" "º" julia-latexsubs) +(puthash "\\1/4" "¼" julia-latexsubs) +(puthash "\\1/2" "½" julia-latexsubs) +(puthash "\\3/4" "¾" julia-latexsubs) +(puthash "\\questiondown" "¿" julia-latexsubs) +(puthash "\\AA" "Å" julia-latexsubs) +(puthash "\\AE" "Æ" julia-latexsubs) +(puthash "\\DH" "Ð" julia-latexsubs) +(puthash "\\times" "×" julia-latexsubs) +(puthash "\\O" "Ø" julia-latexsubs) +(puthash "\\TH" "Þ" julia-latexsubs) +(puthash "\\ss" "ß" julia-latexsubs) +(puthash "\\aa" "å" julia-latexsubs) +(puthash "\\ae" "æ" julia-latexsubs) +(puthash "\\eth" "ð" julia-latexsubs) +(puthash "\\dh" "ð" julia-latexsubs) +(puthash "\\div" "÷" julia-latexsubs) +(puthash "\\o" "ø" julia-latexsubs) +(puthash "\\th" "þ" julia-latexsubs) +(puthash "\\DJ" "Đ" julia-latexsubs) +(puthash "\\dj" "đ" julia-latexsubs) +(puthash "\\hbar" "ħ" julia-latexsubs) +(puthash "\\imath" "ı" julia-latexsubs) +(puthash "\\L" "Ł" julia-latexsubs) +(puthash "\\l" "ł" julia-latexsubs) +(puthash "\\NG" "Ŋ" julia-latexsubs) +(puthash "\\ng" "ŋ" julia-latexsubs) +(puthash "\\OE" "Œ" julia-latexsubs) +(puthash "\\oe" "œ" julia-latexsubs) +(puthash "\\hvlig" "ƕ" julia-latexsubs) +(puthash "\\nrleg" "ƞ" julia-latexsubs) +(puthash "\\Zbar" "Ƶ" julia-latexsubs) +(puthash "\\doublepipe" "ǂ" julia-latexsubs) +(puthash "\\jmath" "ȷ" julia-latexsubs) +(puthash "\\trna" "ɐ" julia-latexsubs) +(puthash "\\trnsa" "ɒ" julia-latexsubs) +(puthash "\\openo" "ɔ" julia-latexsubs) +(puthash "\\rtld" "ɖ" julia-latexsubs) +(puthash "\\schwa" "ə" julia-latexsubs) +(puthash "\\pgamma" "ɣ" julia-latexsubs) +(puthash "\\pbgam" "ɤ" julia-latexsubs) +(puthash "\\trnh" "ɥ" julia-latexsubs) +(puthash "\\btdl" "ɬ" julia-latexsubs) +(puthash "\\rtll" "ɭ" julia-latexsubs) +(puthash "\\trnm" "ɯ" julia-latexsubs) +(puthash "\\trnmlr" "ɰ" julia-latexsubs) +(puthash "\\ltlmr" "ɱ" julia-latexsubs) +(puthash "\\ltln" "ɲ" julia-latexsubs) +(puthash "\\rtln" "ɳ" julia-latexsubs) +(puthash "\\clomeg" "ɷ" julia-latexsubs) +(puthash "\\ltphi" "ɸ" julia-latexsubs) +(puthash "\\trnr" "ɹ" julia-latexsubs) +(puthash "\\trnrl" "ɺ" julia-latexsubs) +(puthash "\\rttrnr" "ɻ" julia-latexsubs) +(puthash "\\rl" "ɼ" julia-latexsubs) +(puthash "\\rtlr" "ɽ" julia-latexsubs) +(puthash "\\fhr" "ɾ" julia-latexsubs) +(puthash "\\rtls" "ʂ" julia-latexsubs) +(puthash "\\esh" "ʃ" julia-latexsubs) +(puthash "\\trnt" "ʇ" julia-latexsubs) +(puthash "\\rtlt" "ʈ" julia-latexsubs) +(puthash "\\pupsil" "ʊ" julia-latexsubs) +(puthash "\\pscrv" "ʋ" julia-latexsubs) +(puthash "\\invv" "ʌ" julia-latexsubs) +(puthash "\\invw" "ʍ" julia-latexsubs) +(puthash "\\trny" "ʎ" julia-latexsubs) +(puthash "\\rtlz" "ʐ" julia-latexsubs) +(puthash "\\yogh" "ʒ" julia-latexsubs) +(puthash "\\glst" "ʔ" julia-latexsubs) +(puthash "\\reglst" "ʕ" julia-latexsubs) +(puthash "\\inglst" "ʖ" julia-latexsubs) +(puthash "\\turnk" "ʞ" julia-latexsubs) +(puthash "\\dyogh" "ʤ" julia-latexsubs) +(puthash "\\tesh" "ʧ" julia-latexsubs) +(puthash "\\^h" "ʰ" julia-latexsubs) +(puthash "\\^j" "ʲ" julia-latexsubs) +(puthash "\\^r" "ʳ" julia-latexsubs) +(puthash "\\^w" "ʷ" julia-latexsubs) +(puthash "\\^y" "ʸ" julia-latexsubs) +(puthash "\\rasp" "ʼ" julia-latexsubs) +(puthash "\\verts" "ˈ" julia-latexsubs) +(puthash "\\verti" "ˌ" julia-latexsubs) +(puthash "\\lmrk" "ː" julia-latexsubs) +(puthash "\\hlmrk" "ˑ" julia-latexsubs) +(puthash "\\sbrhr" "˒" julia-latexsubs) +(puthash "\\sblhr" "˓" julia-latexsubs) +(puthash "\\rais" "˔" julia-latexsubs) +(puthash "\\low" "˕" julia-latexsubs) +(puthash "\\u" "˘" julia-latexsubs) +(puthash "\\tildelow" "˜" julia-latexsubs) +(puthash "\\^l" "ˡ" julia-latexsubs) +(puthash "\\^s" "ˢ" julia-latexsubs) +(puthash "\\^x" "ˣ" julia-latexsubs) +(puthash "\\grave" "̀" julia-latexsubs) +(puthash "\\acute" "́" julia-latexsubs) +(puthash "\\hat" "̂" julia-latexsubs) +(puthash "\\tilde" "̃" julia-latexsubs) +(puthash "\\bar" "̄" julia-latexsubs) +(puthash "\\overbar" "̅" julia-latexsubs) +(puthash "\\breve" "̆" julia-latexsubs) +(puthash "\\dot" "̇" julia-latexsubs) +(puthash "\\ddot" "̈" julia-latexsubs) +(puthash "\\ovhook" "̉" julia-latexsubs) +(puthash "\\ocirc" "̊" julia-latexsubs) +(puthash "\\H" "̋" julia-latexsubs) +(puthash "\\check" "̌" julia-latexsubs) +(puthash "\\candra" "̐" julia-latexsubs) +(puthash "\\oturnedcomma" "̒" julia-latexsubs) +(puthash "\\ocommatopright" "̕" julia-latexsubs) +(puthash "\\droang" "̚" julia-latexsubs) +(puthash "\\palh" "̡" julia-latexsubs) +(puthash "\\rh" "̢" julia-latexsubs) +(puthash "\\c" "̧" julia-latexsubs) +(puthash "\\k" "̨" julia-latexsubs) +(puthash "\\sbbrg" "̪" julia-latexsubs) +(puthash "\\wideutilde" "̰" julia-latexsubs) +(puthash "\\underbar" "̲" julia-latexsubs) +(puthash "\\strike" "̶" julia-latexsubs) +(puthash "\\sout" "̶" julia-latexsubs) +(puthash "\\not" "̸" julia-latexsubs) +(puthash "\\underleftrightarrow" "͍" julia-latexsubs) +(puthash "\\Alpha" "Α" julia-latexsubs) +(puthash "\\Beta" "Β" julia-latexsubs) +(puthash "\\Gamma" "Γ" julia-latexsubs) +(puthash "\\Delta" "Δ" julia-latexsubs) +(puthash "\\Epsilon" "Ε" julia-latexsubs) +(puthash "\\Zeta" "Ζ" julia-latexsubs) +(puthash "\\Eta" "Η" julia-latexsubs) +(puthash "\\Theta" "Θ" julia-latexsubs) +(puthash "\\Iota" "Ι" julia-latexsubs) +(puthash "\\Kappa" "Κ" julia-latexsubs) +(puthash "\\Lambda" "Λ" julia-latexsubs) +(puthash "\\upMu" "Μ" julia-latexsubs) +(puthash "\\upNu" "Ν" julia-latexsubs) +(puthash "\\Xi" "Ξ" julia-latexsubs) +(puthash "\\upOmicron" "Ο" julia-latexsubs) +(puthash "\\Pi" "Π" julia-latexsubs) +(puthash "\\Rho" "Ρ" julia-latexsubs) +(puthash "\\Sigma" "Σ" julia-latexsubs) +(puthash "\\Tau" "Τ" julia-latexsubs) +(puthash "\\Upsilon" "Υ" julia-latexsubs) +(puthash "\\Phi" "Φ" julia-latexsubs) +(puthash "\\Chi" "Χ" julia-latexsubs) +(puthash "\\Psi" "Ψ" julia-latexsubs) +(puthash "\\Omega" "Ω" julia-latexsubs) +(puthash "\\alpha" "α" julia-latexsubs) +(puthash "\\beta" "β" julia-latexsubs) +(puthash "\\gamma" "γ" julia-latexsubs) +(puthash "\\delta" "δ" julia-latexsubs) +(puthash "\\upepsilon" "ε" julia-latexsubs) +(puthash "\\varepsilon" "ε" julia-latexsubs) +(puthash "\\zeta" "ζ" julia-latexsubs) +(puthash "\\eta" "η" julia-latexsubs) +(puthash "\\theta" "θ" julia-latexsubs) +(puthash "\\iota" "ι" julia-latexsubs) +(puthash "\\kappa" "κ" julia-latexsubs) +(puthash "\\lambda" "λ" julia-latexsubs) +(puthash "\\mu" "μ" julia-latexsubs) +(puthash "\\nu" "ν" julia-latexsubs) +(puthash "\\xi" "ξ" julia-latexsubs) +(puthash "\\upomicron" "ο" julia-latexsubs) +(puthash "\\pi" "π" julia-latexsubs) +(puthash "\\rho" "ρ" julia-latexsubs) +(puthash "\\varsigma" "ς" julia-latexsubs) +(puthash "\\sigma" "σ" julia-latexsubs) +(puthash "\\tau" "τ" julia-latexsubs) +(puthash "\\upsilon" "υ" julia-latexsubs) +(puthash "\\varphi" "φ" julia-latexsubs) +(puthash "\\chi" "χ" julia-latexsubs) +(puthash "\\psi" "ψ" julia-latexsubs) +(puthash "\\omega" "ω" julia-latexsubs) +(puthash "\\upvarbeta" "ϐ" julia-latexsubs) +(puthash "\\vartheta" "ϑ" julia-latexsubs) +(puthash "\\phi" "ϕ" julia-latexsubs) +(puthash "\\varpi" "ϖ" julia-latexsubs) +(puthash "\\upoldKoppa" "Ϙ" julia-latexsubs) +(puthash "\\upoldkoppa" "ϙ" julia-latexsubs) +(puthash "\\Stigma" "Ϛ" julia-latexsubs) +(puthash "\\upstigma" "ϛ" julia-latexsubs) +(puthash "\\Digamma" "Ϝ" julia-latexsubs) +(puthash "\\digamma" "ϝ" julia-latexsubs) +(puthash "\\Koppa" "Ϟ" julia-latexsubs) +(puthash "\\upkoppa" "ϟ" julia-latexsubs) +(puthash "\\Sampi" "Ϡ" julia-latexsubs) +(puthash "\\upsampi" "ϡ" julia-latexsubs) +(puthash "\\varkappa" "ϰ" julia-latexsubs) +(puthash "\\varrho" "ϱ" julia-latexsubs) +(puthash "\\varTheta" "ϴ" julia-latexsubs) +(puthash "\\epsilon" "ϵ" julia-latexsubs) +(puthash "\\backepsilon" "϶" julia-latexsubs) +(puthash "\\^A" "ᴬ" julia-latexsubs) +(puthash "\\^B" "ᴮ" julia-latexsubs) +(puthash "\\^D" "ᴰ" julia-latexsubs) +(puthash "\\^E" "ᴱ" julia-latexsubs) +(puthash "\\^G" "ᴳ" julia-latexsubs) +(puthash "\\^H" "ᴴ" julia-latexsubs) +(puthash "\\^I" "ᴵ" julia-latexsubs) +(puthash "\\^J" "ᴶ" julia-latexsubs) +(puthash "\\^K" "ᴷ" julia-latexsubs) +(puthash "\\^L" "ᴸ" julia-latexsubs) +(puthash "\\^M" "ᴹ" julia-latexsubs) +(puthash "\\^N" "ᴺ" julia-latexsubs) +(puthash "\\^O" "ᴼ" julia-latexsubs) +(puthash "\\^P" "ᴾ" julia-latexsubs) +(puthash "\\^R" "ᴿ" julia-latexsubs) +(puthash "\\^T" "ᵀ" julia-latexsubs) +(puthash "\\^U" "ᵁ" julia-latexsubs) +(puthash "\\^W" "ᵂ" julia-latexsubs) +(puthash "\\^a" "ᵃ" julia-latexsubs) +(puthash "\\^alpha" "ᵅ" julia-latexsubs) +(puthash "\\^b" "ᵇ" julia-latexsubs) +(puthash "\\^d" "ᵈ" julia-latexsubs) +(puthash "\\^e" "ᵉ" julia-latexsubs) +(puthash "\\^epsilon" "ᵋ" julia-latexsubs) +(puthash "\\^g" "ᵍ" julia-latexsubs) +(puthash "\\^k" "ᵏ" julia-latexsubs) +(puthash "\\^m" "ᵐ" julia-latexsubs) +(puthash "\\^o" "ᵒ" julia-latexsubs) +(puthash "\\^p" "ᵖ" julia-latexsubs) +(puthash "\\^t" "ᵗ" julia-latexsubs) +(puthash "\\^u" "ᵘ" julia-latexsubs) +(puthash "\\^v" "ᵛ" julia-latexsubs) +(puthash "\\^beta" "ᵝ" julia-latexsubs) +(puthash "\\^gamma" "ᵞ" julia-latexsubs) +(puthash "\\^delta" "ᵟ" julia-latexsubs) +(puthash "\\^phi" "ᵠ" julia-latexsubs) +(puthash "\\^chi" "ᵡ" julia-latexsubs) +(puthash "\\_i" "ᵢ" julia-latexsubs) +(puthash "\\_r" "ᵣ" julia-latexsubs) +(puthash "\\_u" "ᵤ" julia-latexsubs) +(puthash "\\_v" "ᵥ" julia-latexsubs) +(puthash "\\_beta" "ᵦ" julia-latexsubs) +(puthash "\\_gamma" "ᵧ" julia-latexsubs) +(puthash "\\_rho" "ᵨ" julia-latexsubs) +(puthash "\\_phi" "ᵩ" julia-latexsubs) +(puthash "\\_chi" "ᵪ" julia-latexsubs) +(puthash "\\^c" "ᶜ" julia-latexsubs) +(puthash "\\^f" "ᶠ" julia-latexsubs) +(puthash "\\^iota" "ᶥ" julia-latexsubs) +(puthash "\\^Phi" "ᶲ" julia-latexsubs) +(puthash "\\^z" "ᶻ" julia-latexsubs) +(puthash "\\^theta" "ᶿ" julia-latexsubs) +(puthash "\\enspace" " " julia-latexsubs) +(puthash "\\quad" " " julia-latexsubs) +(puthash "\\thickspace" " " julia-latexsubs) +(puthash "\\thinspace" " " julia-latexsubs) +(puthash "\\hspace" " " julia-latexsubs) +(puthash "\\endash" "–" julia-latexsubs) +(puthash "\\emdash" "—" julia-latexsubs) +(puthash "\\Vert" "‖" julia-latexsubs) +(puthash "\\lq" "‘" julia-latexsubs) +(puthash "\\rq" "’" julia-latexsubs) +(puthash "\\reapos" "‛" julia-latexsubs) +(puthash "\\quotedblleft" "“" julia-latexsubs) +(puthash "\\quotedblright" "”" julia-latexsubs) +(puthash "\\dagger" "†" julia-latexsubs) +(puthash "\\ddagger" "‡" julia-latexsubs) +(puthash "\\bullet" "•" julia-latexsubs) +(puthash "\\dots" "…" julia-latexsubs) +(puthash "\\ldots" "…" julia-latexsubs) +(puthash "\\perthousand" "‰" julia-latexsubs) +(puthash "\\pertenthousand" "‱" julia-latexsubs) +(puthash "\\prime" "′" julia-latexsubs) +(puthash "\\pprime" "″" julia-latexsubs) +(puthash "\\ppprime" "‴" julia-latexsubs) +(puthash "\\backprime" "‵" julia-latexsubs) +(puthash "\\backpprime" "‶" julia-latexsubs) +(puthash "\\backppprime" "‷" julia-latexsubs) +(puthash "\\guilsinglleft" "‹" julia-latexsubs) +(puthash "\\guilsinglright" "›" julia-latexsubs) +(puthash "\\:bangbang:" "‼" julia-latexsubs) +(puthash "\\tieconcat" "⁀" julia-latexsubs) +(puthash "\\:interrobang:" "⁉" julia-latexsubs) +(puthash "\\pppprime" "⁗" julia-latexsubs) +(puthash "\\tricolon" "⁝" julia-latexsubs) +(puthash "\\nolinebreak" "\u2060" julia-latexsubs) +(puthash "\\^0" "⁰" julia-latexsubs) +(puthash "\\^i" "ⁱ" julia-latexsubs) +(puthash "\\^4" "⁴" julia-latexsubs) +(puthash "\\^5" "⁵" julia-latexsubs) +(puthash "\\^6" "⁶" julia-latexsubs) +(puthash "\\^7" "⁷" julia-latexsubs) +(puthash "\\^8" "⁸" julia-latexsubs) +(puthash "\\^9" "⁹" julia-latexsubs) +(puthash "\\^+" "⁺" julia-latexsubs) +(puthash "\\^-" "⁻" julia-latexsubs) +(puthash "\\^=" "⁼" julia-latexsubs) +(puthash "\\^(" "⁽" julia-latexsubs) +(puthash "\\^)" "⁾" julia-latexsubs) +(puthash "\\^n" "ⁿ" julia-latexsubs) +(puthash "\\_0" "₀" julia-latexsubs) +(puthash "\\_1" "₁" julia-latexsubs) +(puthash "\\_2" "₂" julia-latexsubs) +(puthash "\\_3" "₃" julia-latexsubs) +(puthash "\\_4" "₄" julia-latexsubs) +(puthash "\\_5" "₅" julia-latexsubs) +(puthash "\\_6" "₆" julia-latexsubs) +(puthash "\\_7" "₇" julia-latexsubs) +(puthash "\\_8" "₈" julia-latexsubs) +(puthash "\\_9" "₉" julia-latexsubs) +(puthash "\\_+" "₊" julia-latexsubs) +(puthash "\\_-" "₋" julia-latexsubs) +(puthash "\\_=" "₌" julia-latexsubs) +(puthash "\\_(" "₍" julia-latexsubs) +(puthash "\\_)" "₎" julia-latexsubs) +(puthash "\\_a" "ₐ" julia-latexsubs) +(puthash "\\_e" "ₑ" julia-latexsubs) +(puthash "\\_o" "ₒ" julia-latexsubs) +(puthash "\\_x" "ₓ" julia-latexsubs) +(puthash "\\_schwa" "ₔ" julia-latexsubs) +(puthash "\\_h" "ₕ" julia-latexsubs) +(puthash "\\_k" "ₖ" julia-latexsubs) +(puthash "\\_l" "ₗ" julia-latexsubs) +(puthash "\\_m" "ₘ" julia-latexsubs) +(puthash "\\_n" "ₙ" julia-latexsubs) +(puthash "\\_p" "ₚ" julia-latexsubs) +(puthash "\\_s" "ₛ" julia-latexsubs) +(puthash "\\_t" "ₜ" julia-latexsubs) +(puthash "\\pes" "₧" julia-latexsubs) +(puthash "\\euro" "€" julia-latexsubs) +(puthash "\\leftharpoonaccent" "⃐" julia-latexsubs) +(puthash "\\rightharpoonaccent" "⃑" julia-latexsubs) +(puthash "\\vertoverlay" "⃒" julia-latexsubs) +(puthash "\\overleftarrow" "⃖" julia-latexsubs) +(puthash "\\vec" "⃗" julia-latexsubs) +(puthash "\\dddot" "⃛" julia-latexsubs) +(puthash "\\ddddot" "⃜" julia-latexsubs) +(puthash "\\enclosecircle" "⃝" julia-latexsubs) +(puthash "\\enclosesquare" "⃞" julia-latexsubs) +(puthash "\\enclosediamond" "⃟" julia-latexsubs) +(puthash "\\overleftrightarrow" "⃡" julia-latexsubs) +(puthash "\\enclosetriangle" "⃤" julia-latexsubs) +(puthash "\\annuity" "⃧" julia-latexsubs) +(puthash "\\threeunderdot" "⃨" julia-latexsubs) +(puthash "\\widebridgeabove" "⃩" julia-latexsubs) +(puthash "\\underrightharpoondown" "⃬" julia-latexsubs) +(puthash "\\underleftharpoondown" "⃭" julia-latexsubs) +(puthash "\\underleftarrow" "⃮" julia-latexsubs) +(puthash "\\underrightarrow" "⃯" julia-latexsubs) +(puthash "\\asteraccent" "⃰" julia-latexsubs) +(puthash "\\bbC" "ℂ" julia-latexsubs) +(puthash "\\eulermascheroni" "ℇ" julia-latexsubs) +(puthash "\\scrg" "ℊ" julia-latexsubs) +(puthash "\\scrH" "ℋ" julia-latexsubs) +(puthash "\\frakH" "ℌ" julia-latexsubs) +(puthash "\\bbH" "ℍ" julia-latexsubs) +(puthash "\\planck" "ℎ" julia-latexsubs) +(puthash "\\hslash" "ℏ" julia-latexsubs) +(puthash "\\scrI" "ℐ" julia-latexsubs) +(puthash "\\Im" "ℑ" julia-latexsubs) +(puthash "\\scrL" "ℒ" julia-latexsubs) +(puthash "\\ell" "ℓ" julia-latexsubs) +(puthash "\\bbN" "ℕ" julia-latexsubs) +(puthash "\\numero" "№" julia-latexsubs) +(puthash "\\wp" "℘" julia-latexsubs) +(puthash "\\bbP" "ℙ" julia-latexsubs) +(puthash "\\bbQ" "ℚ" julia-latexsubs) +(puthash "\\scrR" "ℛ" julia-latexsubs) +(puthash "\\Re" "ℜ" julia-latexsubs) +(puthash "\\bbR" "ℝ" julia-latexsubs) +(puthash "\\xrat" "℞" julia-latexsubs) +(puthash "\\trademark" "™" julia-latexsubs) +(puthash "\\:tm:" "™" julia-latexsubs) +(puthash "\\bbZ" "ℤ" julia-latexsubs) +(puthash "\\ohm" "Ω" julia-latexsubs) +(puthash "\\mho" "℧" julia-latexsubs) +(puthash "\\frakZ" "ℨ" julia-latexsubs) +(puthash "\\turnediota" "℩" julia-latexsubs) +(puthash "\\Angstrom" "Å" julia-latexsubs) +(puthash "\\scrB" "ℬ" julia-latexsubs) +(puthash "\\frakC" "ℭ" julia-latexsubs) +(puthash "\\scre" "ℯ" julia-latexsubs) +(puthash "\\euler" "ℯ" julia-latexsubs) +(puthash "\\scrE" "ℰ" julia-latexsubs) +(puthash "\\scrF" "ℱ" julia-latexsubs) +(puthash "\\Finv" "Ⅎ" julia-latexsubs) +(puthash "\\scrM" "ℳ" julia-latexsubs) +(puthash "\\scro" "ℴ" julia-latexsubs) +(puthash "\\aleph" "ℵ" julia-latexsubs) +(puthash "\\beth" "ℶ" julia-latexsubs) +(puthash "\\gimel" "ℷ" julia-latexsubs) +(puthash "\\daleth" "ℸ" julia-latexsubs) +(puthash "\\:information_source:" "ℹ" julia-latexsubs) +(puthash "\\bbpi" "ℼ" julia-latexsubs) +(puthash "\\bbgamma" "ℽ" julia-latexsubs) +(puthash "\\bbGamma" "ℾ" julia-latexsubs) +(puthash "\\bbPi" "ℿ" julia-latexsubs) +(puthash "\\bbsum" "⅀" julia-latexsubs) +(puthash "\\Game" "⅁" julia-latexsubs) +(puthash "\\sansLturned" "⅂" julia-latexsubs) +(puthash "\\sansLmirrored" "⅃" julia-latexsubs) +(puthash "\\Yup" "⅄" julia-latexsubs) +(puthash "\\bbiD" "ⅅ" julia-latexsubs) +(puthash "\\bbid" "ⅆ" julia-latexsubs) +(puthash "\\bbie" "ⅇ" julia-latexsubs) +(puthash "\\bbii" "ⅈ" julia-latexsubs) +(puthash "\\bbij" "ⅉ" julia-latexsubs) +(puthash "\\PropertyLine" "⅊" julia-latexsubs) +(puthash "\\upand" "⅋" julia-latexsubs) +(puthash "\\1/7" "⅐" julia-latexsubs) +(puthash "\\1/9" "⅑" julia-latexsubs) +(puthash "\\1/10" "⅒" julia-latexsubs) +(puthash "\\1/3" "⅓" julia-latexsubs) +(puthash "\\2/3" "⅔" julia-latexsubs) +(puthash "\\1/5" "⅕" julia-latexsubs) +(puthash "\\2/5" "⅖" julia-latexsubs) +(puthash "\\3/5" "⅗" julia-latexsubs) +(puthash "\\4/5" "⅘" julia-latexsubs) +(puthash "\\1/6" "⅙" julia-latexsubs) +(puthash "\\5/6" "⅚" julia-latexsubs) +(puthash "\\1/8" "⅛" julia-latexsubs) +(puthash "\\3/8" "⅜" julia-latexsubs) +(puthash "\\5/8" "⅝" julia-latexsubs) +(puthash "\\7/8" "⅞" julia-latexsubs) +(puthash "\\1/" "⅟" julia-latexsubs) +(puthash "\\0/3" "↉" julia-latexsubs) +(puthash "\\leftarrow" "←" julia-latexsubs) +(puthash "\\uparrow" "↑" julia-latexsubs) +(puthash "\\rightarrow" "→" julia-latexsubs) +(puthash "\\to" "→" julia-latexsubs) +(puthash "\\downarrow" "↓" julia-latexsubs) +(puthash "\\:left_right_arrow:" "↔" julia-latexsubs) +(puthash "\\leftrightarrow" "↔" julia-latexsubs) +(puthash "\\:arrow_up_down:" "↕" julia-latexsubs) +(puthash "\\updownarrow" "↕" julia-latexsubs) +(puthash "\\:arrow_upper_left:" "↖" julia-latexsubs) +(puthash "\\nwarrow" "↖" julia-latexsubs) +(puthash "\\nearrow" "↗" julia-latexsubs) +(puthash "\\:arrow_upper_right:" "↗" julia-latexsubs) +(puthash "\\:arrow_lower_right:" "↘" julia-latexsubs) +(puthash "\\searrow" "↘" julia-latexsubs) +(puthash "\\swarrow" "↙" julia-latexsubs) +(puthash "\\:arrow_lower_left:" "↙" julia-latexsubs) +(puthash "\\nleftarrow" "↚" julia-latexsubs) +(puthash "\\nrightarrow" "↛" julia-latexsubs) +(puthash "\\leftwavearrow" "↜" julia-latexsubs) +(puthash "\\rightwavearrow" "↝" julia-latexsubs) +(puthash "\\twoheadleftarrow" "↞" julia-latexsubs) +(puthash "\\twoheaduparrow" "↟" julia-latexsubs) +(puthash "\\twoheadrightarrow" "↠" julia-latexsubs) +(puthash "\\twoheaddownarrow" "↡" julia-latexsubs) +(puthash "\\leftarrowtail" "↢" julia-latexsubs) +(puthash "\\rightarrowtail" "↣" julia-latexsubs) +(puthash "\\mapsfrom" "↤" julia-latexsubs) +(puthash "\\mapsup" "↥" julia-latexsubs) +(puthash "\\mapsto" "↦" julia-latexsubs) +(puthash "\\mapsdown" "↧" julia-latexsubs) +(puthash "\\updownarrowbar" "↨" julia-latexsubs) +(puthash "\\hookleftarrow" "↩" julia-latexsubs) +(puthash "\\:leftwards_arrow_with_hook:" "↩" julia-latexsubs) +(puthash "\\:arrow_right_hook:" "↪" julia-latexsubs) +(puthash "\\hookrightarrow" "↪" julia-latexsubs) +(puthash "\\looparrowleft" "↫" julia-latexsubs) +(puthash "\\looparrowright" "↬" julia-latexsubs) +(puthash "\\leftrightsquigarrow" "↭" julia-latexsubs) +(puthash "\\nleftrightarrow" "↮" julia-latexsubs) +(puthash "\\downzigzagarrow" "↯" julia-latexsubs) +(puthash "\\Lsh" "↰" julia-latexsubs) +(puthash "\\Rsh" "↱" julia-latexsubs) +(puthash "\\Ldsh" "↲" julia-latexsubs) +(puthash "\\Rdsh" "↳" julia-latexsubs) +(puthash "\\linefeed" "↴" julia-latexsubs) +(puthash "\\carriagereturn" "↵" julia-latexsubs) +(puthash "\\curvearrowleft" "↶" julia-latexsubs) +(puthash "\\curvearrowright" "↷" julia-latexsubs) +(puthash "\\barovernorthwestarrow" "↸" julia-latexsubs) +(puthash "\\barleftarrowrightarrowbar" "↹" julia-latexsubs) +(puthash "\\circlearrowleft" "↺" julia-latexsubs) +(puthash "\\circlearrowright" "↻" julia-latexsubs) +(puthash "\\leftharpoonup" "↼" julia-latexsubs) +(puthash "\\leftharpoondown" "↽" julia-latexsubs) +(puthash "\\upharpoonright" "↾" julia-latexsubs) +(puthash "\\upharpoonleft" "↿" julia-latexsubs) +(puthash "\\rightharpoonup" "⇀" julia-latexsubs) +(puthash "\\rightharpoondown" "⇁" julia-latexsubs) +(puthash "\\downharpoonright" "⇂" julia-latexsubs) +(puthash "\\downharpoonleft" "⇃" julia-latexsubs) +(puthash "\\rightleftarrows" "⇄" julia-latexsubs) +(puthash "\\dblarrowupdown" "⇅" julia-latexsubs) +(puthash "\\leftrightarrows" "⇆" julia-latexsubs) +(puthash "\\leftleftarrows" "⇇" julia-latexsubs) +(puthash "\\upuparrows" "⇈" julia-latexsubs) +(puthash "\\rightrightarrows" "⇉" julia-latexsubs) +(puthash "\\downdownarrows" "⇊" julia-latexsubs) +(puthash "\\leftrightharpoons" "⇋" julia-latexsubs) +(puthash "\\rightleftharpoons" "⇌" julia-latexsubs) +(puthash "\\nLeftarrow" "⇍" julia-latexsubs) +(puthash "\\nLeftrightarrow" "⇎" julia-latexsubs) +(puthash "\\nRightarrow" "⇏" julia-latexsubs) +(puthash "\\Leftarrow" "⇐" julia-latexsubs) +(puthash "\\Uparrow" "⇑" julia-latexsubs) +(puthash "\\Rightarrow" "⇒" julia-latexsubs) +(puthash "\\Downarrow" "⇓" julia-latexsubs) +(puthash "\\Leftrightarrow" "⇔" julia-latexsubs) +(puthash "\\Updownarrow" "⇕" julia-latexsubs) +(puthash "\\Nwarrow" "⇖" julia-latexsubs) +(puthash "\\Nearrow" "⇗" julia-latexsubs) +(puthash "\\Searrow" "⇘" julia-latexsubs) +(puthash "\\Swarrow" "⇙" julia-latexsubs) +(puthash "\\Lleftarrow" "⇚" julia-latexsubs) +(puthash "\\Rrightarrow" "⇛" julia-latexsubs) +(puthash "\\leftsquigarrow" "⇜" julia-latexsubs) +(puthash "\\rightsquigarrow" "⇝" julia-latexsubs) +(puthash "\\nHuparrow" "⇞" julia-latexsubs) +(puthash "\\nHdownarrow" "⇟" julia-latexsubs) +(puthash "\\leftdasharrow" "⇠" julia-latexsubs) +(puthash "\\updasharrow" "⇡" julia-latexsubs) +(puthash "\\rightdasharrow" "⇢" julia-latexsubs) +(puthash "\\downdasharrow" "⇣" julia-latexsubs) +(puthash "\\barleftarrow" "⇤" julia-latexsubs) +(puthash "\\rightarrowbar" "⇥" julia-latexsubs) +(puthash "\\leftwhitearrow" "⇦" julia-latexsubs) +(puthash "\\upwhitearrow" "⇧" julia-latexsubs) +(puthash "\\rightwhitearrow" "⇨" julia-latexsubs) +(puthash "\\downwhitearrow" "⇩" julia-latexsubs) +(puthash "\\whitearrowupfrombar" "⇪" julia-latexsubs) +(puthash "\\circleonrightarrow" "⇴" julia-latexsubs) +(puthash "\\DownArrowUpArrow" "⇵" julia-latexsubs) +(puthash "\\rightthreearrows" "⇶" julia-latexsubs) +(puthash "\\nvleftarrow" "⇷" julia-latexsubs) +(puthash "\\nvrightarrow" "⇸" julia-latexsubs) +(puthash "\\nvleftrightarrow" "⇹" julia-latexsubs) +(puthash "\\nVleftarrow" "⇺" julia-latexsubs) +(puthash "\\nVrightarrow" "⇻" julia-latexsubs) +(puthash "\\nVleftrightarrow" "⇼" julia-latexsubs) +(puthash "\\leftarrowtriangle" "⇽" julia-latexsubs) +(puthash "\\rightarrowtriangle" "⇾" julia-latexsubs) +(puthash "\\leftrightarrowtriangle" "⇿" julia-latexsubs) +(puthash "\\forall" "∀" julia-latexsubs) +(puthash "\\complement" "∁" julia-latexsubs) +(puthash "\\partial" "∂" julia-latexsubs) +(puthash "\\exists" "∃" julia-latexsubs) +(puthash "\\nexists" "∄" julia-latexsubs) +(puthash "\\varnothing" "∅" julia-latexsubs) +(puthash "\\emptyset" "∅" julia-latexsubs) +(puthash "\\increment" "∆" julia-latexsubs) +(puthash "\\del" "∇" julia-latexsubs) +(puthash "\\nabla" "∇" julia-latexsubs) +(puthash "\\in" "∈" julia-latexsubs) +(puthash "\\notin" "∉" julia-latexsubs) +(puthash "\\smallin" "∊" julia-latexsubs) +(puthash "\\ni" "∋" julia-latexsubs) +(puthash "\\nni" "∌" julia-latexsubs) +(puthash "\\smallni" "∍" julia-latexsubs) +(puthash "\\QED" "∎" julia-latexsubs) +(puthash "\\prod" "∏" julia-latexsubs) +(puthash "\\coprod" "∐" julia-latexsubs) +(puthash "\\sum" "∑" julia-latexsubs) +(puthash "\\minus" "−" julia-latexsubs) +(puthash "\\mp" "∓" julia-latexsubs) +(puthash "\\dotplus" "∔" julia-latexsubs) +(puthash "\\setminus" "∖" julia-latexsubs) +(puthash "\\ast" "∗" julia-latexsubs) +(puthash "\\circ" "∘" julia-latexsubs) +(puthash "\\vysmblkcircle" "∙" julia-latexsubs) +(puthash "\\sqrt" "√" julia-latexsubs) +(puthash "\\surd" "√" julia-latexsubs) +(puthash "\\cbrt" "∛" julia-latexsubs) +(puthash "\\fourthroot" "∜" julia-latexsubs) +(puthash "\\propto" "∝" julia-latexsubs) +(puthash "\\infty" "∞" julia-latexsubs) +(puthash "\\rightangle" "∟" julia-latexsubs) +(puthash "\\angle" "∠" julia-latexsubs) +(puthash "\\measuredangle" "∡" julia-latexsubs) +(puthash "\\sphericalangle" "∢" julia-latexsubs) +(puthash "\\mid" "∣" julia-latexsubs) +(puthash "\\nmid" "∤" julia-latexsubs) +(puthash "\\parallel" "∥" julia-latexsubs) +(puthash "\\nparallel" "∦" julia-latexsubs) +(puthash "\\wedge" "∧" julia-latexsubs) +(puthash "\\vee" "∨" julia-latexsubs) +(puthash "\\cap" "∩" julia-latexsubs) +(puthash "\\cup" "∪" julia-latexsubs) +(puthash "\\int" "∫" julia-latexsubs) +(puthash "\\iint" "∬" julia-latexsubs) +(puthash "\\iiint" "∭" julia-latexsubs) +(puthash "\\oint" "∮" julia-latexsubs) +(puthash "\\oiint" "∯" julia-latexsubs) +(puthash "\\oiiint" "∰" julia-latexsubs) +(puthash "\\clwintegral" "∱" julia-latexsubs) +(puthash "\\varointclockwise" "∲" julia-latexsubs) +(puthash "\\ointctrclockwise" "∳" julia-latexsubs) +(puthash "\\therefore" "∴" julia-latexsubs) +(puthash "\\because" "∵" julia-latexsubs) +(puthash "\\Colon" "∷" julia-latexsubs) +(puthash "\\dotminus" "∸" julia-latexsubs) +(puthash "\\dotsminusdots" "∺" julia-latexsubs) +(puthash "\\kernelcontraction" "∻" julia-latexsubs) +(puthash "\\sim" "∼" julia-latexsubs) +(puthash "\\backsim" "∽" julia-latexsubs) +(puthash "\\lazysinv" "∾" julia-latexsubs) +(puthash "\\sinewave" "∿" julia-latexsubs) +(puthash "\\wr" "≀" julia-latexsubs) +(puthash "\\nsim" "≁" julia-latexsubs) +(puthash "\\eqsim" "≂" julia-latexsubs) +(puthash "\\neqsim" "≂̸" julia-latexsubs) +(puthash "\\simeq" "≃" julia-latexsubs) +(puthash "\\nsime" "≄" julia-latexsubs) +(puthash "\\cong" "≅" julia-latexsubs) +(puthash "\\approxnotequal" "≆" julia-latexsubs) +(puthash "\\ncong" "≇" julia-latexsubs) +(puthash "\\approx" "≈" julia-latexsubs) +(puthash "\\napprox" "≉" julia-latexsubs) +(puthash "\\approxeq" "≊" julia-latexsubs) +(puthash "\\tildetrpl" "≋" julia-latexsubs) +(puthash "\\allequal" "≌" julia-latexsubs) +(puthash "\\asymp" "≍" julia-latexsubs) +(puthash "\\Bumpeq" "≎" julia-latexsubs) +(puthash "\\nBumpeq" "≎̸" julia-latexsubs) +(puthash "\\bumpeq" "≏" julia-latexsubs) +(puthash "\\nbumpeq" "≏̸" julia-latexsubs) +(puthash "\\doteq" "≐" julia-latexsubs) +(puthash "\\Doteq" "≑" julia-latexsubs) +(puthash "\\fallingdotseq" "≒" julia-latexsubs) +(puthash "\\risingdotseq" "≓" julia-latexsubs) +(puthash "\\coloneq" "≔" julia-latexsubs) +(puthash "\\eqcolon" "≕" julia-latexsubs) +(puthash "\\eqcirc" "≖" julia-latexsubs) +(puthash "\\circeq" "≗" julia-latexsubs) +(puthash "\\arceq" "≘" julia-latexsubs) +(puthash "\\wedgeq" "≙" julia-latexsubs) +(puthash "\\veeeq" "≚" julia-latexsubs) +(puthash "\\starequal" "≛" julia-latexsubs) +(puthash "\\triangleq" "≜" julia-latexsubs) +(puthash "\\eqdef" "≝" julia-latexsubs) +(puthash "\\measeq" "≞" julia-latexsubs) +(puthash "\\questeq" "≟" julia-latexsubs) +(puthash "\\ne" "≠" julia-latexsubs) +(puthash "\\equiv" "≡" julia-latexsubs) +(puthash "\\nequiv" "≢" julia-latexsubs) +(puthash "\\Equiv" "≣" julia-latexsubs) +(puthash "\\le" "≤" julia-latexsubs) +(puthash "\\leq" "≤" julia-latexsubs) +(puthash "\\ge" "≥" julia-latexsubs) +(puthash "\\geq" "≥" julia-latexsubs) +(puthash "\\leqq" "≦" julia-latexsubs) +(puthash "\\geqq" "≧" julia-latexsubs) +(puthash "\\lneqq" "≨" julia-latexsubs) +(puthash "\\lvertneqq" "≨︀" julia-latexsubs) +(puthash "\\gneqq" "≩" julia-latexsubs) +(puthash "\\gvertneqq" "≩︀" julia-latexsubs) +(puthash "\\ll" "≪" julia-latexsubs) +(puthash "\\NotLessLess" "≪̸" julia-latexsubs) +(puthash "\\gg" "≫" julia-latexsubs) +(puthash "\\NotGreaterGreater" "≫̸" julia-latexsubs) +(puthash "\\between" "≬" julia-latexsubs) +(puthash "\\nasymp" "≭" julia-latexsubs) +(puthash "\\nless" "≮" julia-latexsubs) +(puthash "\\ngtr" "≯" julia-latexsubs) +(puthash "\\nleq" "≰" julia-latexsubs) +(puthash "\\ngeq" "≱" julia-latexsubs) +(puthash "\\lesssim" "≲" julia-latexsubs) +(puthash "\\gtrsim" "≳" julia-latexsubs) +(puthash "\\nlesssim" "≴" julia-latexsubs) +(puthash "\\ngtrsim" "≵" julia-latexsubs) +(puthash "\\lessgtr" "≶" julia-latexsubs) +(puthash "\\gtrless" "≷" julia-latexsubs) +(puthash "\\notlessgreater" "≸" julia-latexsubs) +(puthash "\\notgreaterless" "≹" julia-latexsubs) +(puthash "\\prec" "≺" julia-latexsubs) +(puthash "\\succ" "≻" julia-latexsubs) +(puthash "\\preccurlyeq" "≼" julia-latexsubs) +(puthash "\\succcurlyeq" "≽" julia-latexsubs) +(puthash "\\precsim" "≾" julia-latexsubs) +(puthash "\\nprecsim" "≾̸" julia-latexsubs) +(puthash "\\succsim" "≿" julia-latexsubs) +(puthash "\\nsuccsim" "≿̸" julia-latexsubs) +(puthash "\\nprec" "⊀" julia-latexsubs) +(puthash "\\nsucc" "⊁" julia-latexsubs) +(puthash "\\subset" "⊂" julia-latexsubs) +(puthash "\\supset" "⊃" julia-latexsubs) +(puthash "\\nsubset" "⊄" julia-latexsubs) +(puthash "\\nsupset" "⊅" julia-latexsubs) +(puthash "\\subseteq" "⊆" julia-latexsubs) +(puthash "\\supseteq" "⊇" julia-latexsubs) +(puthash "\\nsubseteq" "⊈" julia-latexsubs) +(puthash "\\nsupseteq" "⊉" julia-latexsubs) +(puthash "\\subsetneq" "⊊" julia-latexsubs) +(puthash "\\varsubsetneqq" "⊊︀" julia-latexsubs) +(puthash "\\supsetneq" "⊋" julia-latexsubs) +(puthash "\\varsupsetneq" "⊋︀" julia-latexsubs) +(puthash "\\cupdot" "⊍" julia-latexsubs) +(puthash "\\uplus" "⊎" julia-latexsubs) +(puthash "\\sqsubset" "⊏" julia-latexsubs) +(puthash "\\NotSquareSubset" "⊏̸" julia-latexsubs) +(puthash "\\sqsupset" "⊐" julia-latexsubs) +(puthash "\\NotSquareSuperset" "⊐̸" julia-latexsubs) +(puthash "\\sqsubseteq" "⊑" julia-latexsubs) +(puthash "\\sqsupseteq" "⊒" julia-latexsubs) +(puthash "\\sqcap" "⊓" julia-latexsubs) +(puthash "\\sqcup" "⊔" julia-latexsubs) +(puthash "\\oplus" "⊕" julia-latexsubs) +(puthash "\\ominus" "⊖" julia-latexsubs) +(puthash "\\otimes" "⊗" julia-latexsubs) +(puthash "\\oslash" "⊘" julia-latexsubs) +(puthash "\\odot" "⊙" julia-latexsubs) +(puthash "\\circledcirc" "⊚" julia-latexsubs) +(puthash "\\circledast" "⊛" julia-latexsubs) +(puthash "\\circledequal" "⊜" julia-latexsubs) +(puthash "\\circleddash" "⊝" julia-latexsubs) +(puthash "\\boxplus" "⊞" julia-latexsubs) +(puthash "\\boxminus" "⊟" julia-latexsubs) +(puthash "\\boxtimes" "⊠" julia-latexsubs) +(puthash "\\boxdot" "⊡" julia-latexsubs) +(puthash "\\vdash" "⊢" julia-latexsubs) +(puthash "\\dashv" "⊣" julia-latexsubs) +(puthash "\\top" "⊤" julia-latexsubs) +(puthash "\\bot" "⊥" julia-latexsubs) +(puthash "\\models" "⊧" julia-latexsubs) +(puthash "\\vDash" "⊨" julia-latexsubs) +(puthash "\\Vdash" "⊩" julia-latexsubs) +(puthash "\\Vvdash" "⊪" julia-latexsubs) +(puthash "\\VDash" "⊫" julia-latexsubs) +(puthash "\\nvdash" "⊬" julia-latexsubs) +(puthash "\\nvDash" "⊭" julia-latexsubs) +(puthash "\\nVdash" "⊮" julia-latexsubs) +(puthash "\\nVDash" "⊯" julia-latexsubs) +(puthash "\\prurel" "⊰" julia-latexsubs) +(puthash "\\scurel" "⊱" julia-latexsubs) +(puthash "\\vartriangleleft" "⊲" julia-latexsubs) +(puthash "\\vartriangleright" "⊳" julia-latexsubs) +(puthash "\\trianglelefteq" "⊴" julia-latexsubs) +(puthash "\\trianglerighteq" "⊵" julia-latexsubs) +(puthash "\\original" "⊶" julia-latexsubs) +(puthash "\\image" "⊷" julia-latexsubs) +(puthash "\\multimap" "⊸" julia-latexsubs) +(puthash "\\hermitconjmatrix" "⊹" julia-latexsubs) +(puthash "\\intercal" "⊺" julia-latexsubs) +(puthash "\\veebar" "⊻" julia-latexsubs) +(puthash "\\xor" "⊻" julia-latexsubs) +(puthash "\\barwedge" "⊼" julia-latexsubs) +(puthash "\\barvee" "⊽" julia-latexsubs) +(puthash "\\rightanglearc" "⊾" julia-latexsubs) +(puthash "\\varlrtriangle" "⊿" julia-latexsubs) +(puthash "\\bigwedge" "⋀" julia-latexsubs) +(puthash "\\bigvee" "⋁" julia-latexsubs) +(puthash "\\bigcap" "⋂" julia-latexsubs) +(puthash "\\bigcup" "⋃" julia-latexsubs) +(puthash "\\diamond" "⋄" julia-latexsubs) +(puthash "\\cdot" "⋅" julia-latexsubs) +(puthash "\\star" "⋆" julia-latexsubs) +(puthash "\\divideontimes" "⋇" julia-latexsubs) +(puthash "\\bowtie" "⋈" julia-latexsubs) +(puthash "\\ltimes" "⋉" julia-latexsubs) +(puthash "\\rtimes" "⋊" julia-latexsubs) +(puthash "\\leftthreetimes" "⋋" julia-latexsubs) +(puthash "\\rightthreetimes" "⋌" julia-latexsubs) +(puthash "\\backsimeq" "⋍" julia-latexsubs) +(puthash "\\curlyvee" "⋎" julia-latexsubs) +(puthash "\\curlywedge" "⋏" julia-latexsubs) +(puthash "\\Subset" "⋐" julia-latexsubs) +(puthash "\\Supset" "⋑" julia-latexsubs) +(puthash "\\Cap" "⋒" julia-latexsubs) +(puthash "\\Cup" "⋓" julia-latexsubs) +(puthash "\\pitchfork" "⋔" julia-latexsubs) +(puthash "\\equalparallel" "⋕" julia-latexsubs) +(puthash "\\lessdot" "⋖" julia-latexsubs) +(puthash "\\gtrdot" "⋗" julia-latexsubs) +(puthash "\\verymuchless" "⋘" julia-latexsubs) +(puthash "\\ggg" "⋙" julia-latexsubs) +(puthash "\\lesseqgtr" "⋚" julia-latexsubs) +(puthash "\\gtreqless" "⋛" julia-latexsubs) +(puthash "\\eqless" "⋜" julia-latexsubs) +(puthash "\\eqgtr" "⋝" julia-latexsubs) +(puthash "\\curlyeqprec" "⋞" julia-latexsubs) +(puthash "\\curlyeqsucc" "⋟" julia-latexsubs) +(puthash "\\npreccurlyeq" "⋠" julia-latexsubs) +(puthash "\\nsucccurlyeq" "⋡" julia-latexsubs) +(puthash "\\nsqsubseteq" "⋢" julia-latexsubs) +(puthash "\\nsqsupseteq" "⋣" julia-latexsubs) +(puthash "\\sqsubsetneq" "⋤" julia-latexsubs) +(puthash "\\sqspne" "⋥" julia-latexsubs) +(puthash "\\lnsim" "⋦" julia-latexsubs) +(puthash "\\gnsim" "⋧" julia-latexsubs) +(puthash "\\precnsim" "⋨" julia-latexsubs) +(puthash "\\succnsim" "⋩" julia-latexsubs) +(puthash "\\ntriangleleft" "⋪" julia-latexsubs) +(puthash "\\ntriangleright" "⋫" julia-latexsubs) +(puthash "\\ntrianglelefteq" "⋬" julia-latexsubs) +(puthash "\\ntrianglerighteq" "⋭" julia-latexsubs) +(puthash "\\vdots" "⋮" julia-latexsubs) +(puthash "\\cdots" "⋯" julia-latexsubs) +(puthash "\\adots" "⋰" julia-latexsubs) +(puthash "\\ddots" "⋱" julia-latexsubs) +(puthash "\\disin" "⋲" julia-latexsubs) +(puthash "\\varisins" "⋳" julia-latexsubs) +(puthash "\\isins" "⋴" julia-latexsubs) +(puthash "\\isindot" "⋵" julia-latexsubs) +(puthash "\\varisinobar" "⋶" julia-latexsubs) +(puthash "\\isinobar" "⋷" julia-latexsubs) +(puthash "\\isinvb" "⋸" julia-latexsubs) +(puthash "\\isinE" "⋹" julia-latexsubs) +(puthash "\\nisd" "⋺" julia-latexsubs) +(puthash "\\varnis" "⋻" julia-latexsubs) +(puthash "\\nis" "⋼" julia-latexsubs) +(puthash "\\varniobar" "⋽" julia-latexsubs) +(puthash "\\niobar" "⋾" julia-latexsubs) +(puthash "\\bagmember" "⋿" julia-latexsubs) +(puthash "\\diameter" "⌀" julia-latexsubs) +(puthash "\\house" "⌂" julia-latexsubs) +(puthash "\\varbarwedge" "⌅" julia-latexsubs) +(puthash "\\vardoublebarwedge" "⌆" julia-latexsubs) +(puthash "\\lceil" "⌈" julia-latexsubs) +(puthash "\\rceil" "⌉" julia-latexsubs) +(puthash "\\lfloor" "⌊" julia-latexsubs) +(puthash "\\rfloor" "⌋" julia-latexsubs) +(puthash "\\invnot" "⌐" julia-latexsubs) +(puthash "\\sqlozenge" "⌑" julia-latexsubs) +(puthash "\\profline" "⌒" julia-latexsubs) +(puthash "\\profsurf" "⌓" julia-latexsubs) +(puthash "\\recorder" "⌕" julia-latexsubs) +(puthash "\\viewdata" "⌗" julia-latexsubs) +(puthash "\\turnednot" "⌙" julia-latexsubs) +(puthash "\\:watch:" "⌚" julia-latexsubs) +(puthash "\\:hourglass:" "⌛" julia-latexsubs) +(puthash "\\ulcorner" "⌜" julia-latexsubs) +(puthash "\\urcorner" "⌝" julia-latexsubs) +(puthash "\\llcorner" "⌞" julia-latexsubs) +(puthash "\\lrcorner" "⌟" julia-latexsubs) +(puthash "\\frown" "⌢" julia-latexsubs) +(puthash "\\smile" "⌣" julia-latexsubs) +(puthash "\\varhexagonlrbonds" "⌬" julia-latexsubs) +(puthash "\\conictaper" "⌲" julia-latexsubs) +(puthash "\\topbot" "⌶" julia-latexsubs) +(puthash "\\obar" "⌽" julia-latexsubs) +(puthash "\\notslash" "⌿" julia-latexsubs) +(puthash "\\notbackslash" "⍀" julia-latexsubs) +(puthash "\\boxupcaret" "⍓" julia-latexsubs) +(puthash "\\boxquestion" "⍰" julia-latexsubs) +(puthash "\\hexagon" "⎔" julia-latexsubs) +(puthash "\\dlcorn" "⎣" julia-latexsubs) +(puthash "\\lmoustache" "⎰" julia-latexsubs) +(puthash "\\rmoustache" "⎱" julia-latexsubs) +(puthash "\\overbracket" "⎴" julia-latexsubs) +(puthash "\\underbracket" "⎵" julia-latexsubs) +(puthash "\\bbrktbrk" "⎶" julia-latexsubs) +(puthash "\\sqrtbottom" "⎷" julia-latexsubs) +(puthash "\\lvboxline" "⎸" julia-latexsubs) +(puthash "\\rvboxline" "⎹" julia-latexsubs) +(puthash "\\varcarriagereturn" "⏎" julia-latexsubs) +(puthash "\\overbrace" "⏞" julia-latexsubs) +(puthash "\\underbrace" "⏟" julia-latexsubs) +(puthash "\\trapezium" "⏢" julia-latexsubs) +(puthash "\\benzenr" "⏣" julia-latexsubs) +(puthash "\\strns" "⏤" julia-latexsubs) +(puthash "\\fltns" "⏥" julia-latexsubs) +(puthash "\\accurrent" "⏦" julia-latexsubs) +(puthash "\\elinters" "⏧" julia-latexsubs) +(puthash "\\:fast_forward:" "⏩" julia-latexsubs) +(puthash "\\:rewind:" "⏪" julia-latexsubs) +(puthash "\\:arrow_double_up:" "⏫" julia-latexsubs) +(puthash "\\:arrow_double_down:" "⏬" julia-latexsubs) +(puthash "\\:alarm_clock:" "⏰" julia-latexsubs) +(puthash "\\:hourglass_flowing_sand:" "⏳" julia-latexsubs) +(puthash "\\blanksymbol" "␢" julia-latexsubs) +(puthash "\\visiblespace" "␣" julia-latexsubs) +(puthash "\\:m:" "Ⓜ" julia-latexsubs) +(puthash "\\circledS" "Ⓢ" julia-latexsubs) +(puthash "\\dshfnc" "┆" julia-latexsubs) +(puthash "\\sqfnw" "┙" julia-latexsubs) +(puthash "\\diagup" "╱" julia-latexsubs) +(puthash "\\diagdown" "╲" julia-latexsubs) +(puthash "\\blockuphalf" "▀" julia-latexsubs) +(puthash "\\blocklowhalf" "▄" julia-latexsubs) +(puthash "\\blockfull" "█" julia-latexsubs) +(puthash "\\blocklefthalf" "▌" julia-latexsubs) +(puthash "\\blockrighthalf" "▐" julia-latexsubs) +(puthash "\\blockqtrshaded" "░" julia-latexsubs) +(puthash "\\blockhalfshaded" "▒" julia-latexsubs) +(puthash "\\blockthreeqtrshaded" "▓" julia-latexsubs) +(puthash "\\blacksquare" "■" julia-latexsubs) +(puthash "\\square" "□" julia-latexsubs) +(puthash "\\squoval" "▢" julia-latexsubs) +(puthash "\\blackinwhitesquare" "▣" julia-latexsubs) +(puthash "\\squarehfill" "▤" julia-latexsubs) +(puthash "\\squarevfill" "▥" julia-latexsubs) +(puthash "\\squarehvfill" "▦" julia-latexsubs) +(puthash "\\squarenwsefill" "▧" julia-latexsubs) +(puthash "\\squareneswfill" "▨" julia-latexsubs) +(puthash "\\squarecrossfill" "▩" julia-latexsubs) +(puthash "\\smblksquare" "▪" julia-latexsubs) +(puthash "\\:black_small_square:" "▪" julia-latexsubs) +(puthash "\\:white_small_square:" "▫" julia-latexsubs) +(puthash "\\smwhtsquare" "▫" julia-latexsubs) +(puthash "\\hrectangleblack" "▬" julia-latexsubs) +(puthash "\\hrectangle" "▭" julia-latexsubs) +(puthash "\\vrectangleblack" "▮" julia-latexsubs) +(puthash "\\vrecto" "▯" julia-latexsubs) +(puthash "\\parallelogramblack" "▰" julia-latexsubs) +(puthash "\\parallelogram" "▱" julia-latexsubs) +(puthash "\\bigblacktriangleup" "▲" julia-latexsubs) +(puthash "\\bigtriangleup" "△" julia-latexsubs) +(puthash "\\blacktriangle" "▴" julia-latexsubs) +(puthash "\\vartriangle" "▵" julia-latexsubs) +(puthash "\\:arrow_forward:" "▶" julia-latexsubs) +(puthash "\\blacktriangleright" "▶" julia-latexsubs) +(puthash "\\triangleright" "▷" julia-latexsubs) +(puthash "\\smallblacktriangleright" "▸" julia-latexsubs) +(puthash "\\smalltriangleright" "▹" julia-latexsubs) +(puthash "\\blackpointerright" "►" julia-latexsubs) +(puthash "\\whitepointerright" "▻" julia-latexsubs) +(puthash "\\bigblacktriangledown" "▼" julia-latexsubs) +(puthash "\\bigtriangledown" "▽" julia-latexsubs) +(puthash "\\blacktriangledown" "▾" julia-latexsubs) +(puthash "\\triangledown" "▿" julia-latexsubs) +(puthash "\\blacktriangleleft" "◀" julia-latexsubs) +(puthash "\\:arrow_backward:" "◀" julia-latexsubs) +(puthash "\\triangleleft" "◁" julia-latexsubs) +(puthash "\\smallblacktriangleleft" "◂" julia-latexsubs) +(puthash "\\smalltriangleleft" "◃" julia-latexsubs) +(puthash "\\blackpointerleft" "◄" julia-latexsubs) +(puthash "\\whitepointerleft" "◅" julia-latexsubs) +(puthash "\\mdlgblkdiamond" "◆" julia-latexsubs) +(puthash "\\mdlgwhtdiamond" "◇" julia-latexsubs) +(puthash "\\blackinwhitediamond" "◈" julia-latexsubs) +(puthash "\\fisheye" "◉" julia-latexsubs) +(puthash "\\lozenge" "◊" julia-latexsubs) +(puthash "\\bigcirc" "○" julia-latexsubs) +(puthash "\\dottedcircle" "◌" julia-latexsubs) +(puthash "\\circlevertfill" "◍" julia-latexsubs) +(puthash "\\bullseye" "◎" julia-latexsubs) +(puthash "\\mdlgblkcircle" "●" julia-latexsubs) +(puthash "\\cirfl" "◐" julia-latexsubs) +(puthash "\\cirfr" "◑" julia-latexsubs) +(puthash "\\cirfb" "◒" julia-latexsubs) +(puthash "\\circletophalfblack" "◓" julia-latexsubs) +(puthash "\\circleurquadblack" "◔" julia-latexsubs) +(puthash "\\blackcircleulquadwhite" "◕" julia-latexsubs) +(puthash "\\blacklefthalfcircle" "◖" julia-latexsubs) +(puthash "\\blackrighthalfcircle" "◗" julia-latexsubs) +(puthash "\\rvbull" "◘" julia-latexsubs) +(puthash "\\inversewhitecircle" "◙" julia-latexsubs) +(puthash "\\invwhiteupperhalfcircle" "◚" julia-latexsubs) +(puthash "\\invwhitelowerhalfcircle" "◛" julia-latexsubs) +(puthash "\\ularc" "◜" julia-latexsubs) +(puthash "\\urarc" "◝" julia-latexsubs) +(puthash "\\lrarc" "◞" julia-latexsubs) +(puthash "\\llarc" "◟" julia-latexsubs) +(puthash "\\topsemicircle" "◠" julia-latexsubs) +(puthash "\\botsemicircle" "◡" julia-latexsubs) +(puthash "\\lrblacktriangle" "◢" julia-latexsubs) +(puthash "\\llblacktriangle" "◣" julia-latexsubs) +(puthash "\\ulblacktriangle" "◤" julia-latexsubs) +(puthash "\\urblacktriangle" "◥" julia-latexsubs) +(puthash "\\smwhtcircle" "◦" julia-latexsubs) +(puthash "\\sqfl" "◧" julia-latexsubs) +(puthash "\\sqfr" "◨" julia-latexsubs) +(puthash "\\squareulblack" "◩" julia-latexsubs) +(puthash "\\sqfse" "◪" julia-latexsubs) +(puthash "\\boxbar" "◫" julia-latexsubs) +(puthash "\\trianglecdot" "◬" julia-latexsubs) +(puthash "\\triangleleftblack" "◭" julia-latexsubs) +(puthash "\\trianglerightblack" "◮" julia-latexsubs) +(puthash "\\lgwhtcircle" "◯" julia-latexsubs) +(puthash "\\squareulquad" "◰" julia-latexsubs) +(puthash "\\squarellquad" "◱" julia-latexsubs) +(puthash "\\squarelrquad" "◲" julia-latexsubs) +(puthash "\\squareurquad" "◳" julia-latexsubs) +(puthash "\\circleulquad" "◴" julia-latexsubs) +(puthash "\\circlellquad" "◵" julia-latexsubs) +(puthash "\\circlelrquad" "◶" julia-latexsubs) +(puthash "\\circleurquad" "◷" julia-latexsubs) +(puthash "\\ultriangle" "◸" julia-latexsubs) +(puthash "\\urtriangle" "◹" julia-latexsubs) +(puthash "\\lltriangle" "◺" julia-latexsubs) +(puthash "\\mdwhtsquare" "◻" julia-latexsubs) +(puthash "\\:white_medium_square:" "◻" julia-latexsubs) +(puthash "\\:black_medium_square:" "◼" julia-latexsubs) +(puthash "\\mdblksquare" "◼" julia-latexsubs) +(puthash "\\:white_medium_small_square:" "◽" julia-latexsubs) +(puthash "\\mdsmwhtsquare" "◽" julia-latexsubs) +(puthash "\\mdsmblksquare" "◾" julia-latexsubs) +(puthash "\\:black_medium_small_square:" "◾" julia-latexsubs) +(puthash "\\lrtriangle" "◿" julia-latexsubs) +(puthash "\\:sunny:" "☀" julia-latexsubs) +(puthash "\\:cloud:" "☁" julia-latexsubs) +(puthash "\\bigstar" "★" julia-latexsubs) +(puthash "\\bigwhitestar" "☆" julia-latexsubs) +(puthash "\\astrosun" "☉" julia-latexsubs) +(puthash "\\:phone:" "☎" julia-latexsubs) +(puthash "\\:ballot_box_with_check:" "☑" julia-latexsubs) +(puthash "\\:umbrella:" "☔" julia-latexsubs) +(puthash "\\:coffee:" "☕" julia-latexsubs) +(puthash "\\:point_up:" "☝" julia-latexsubs) +(puthash "\\danger" "☡" julia-latexsubs) +(puthash "\\:relaxed:" "☺" julia-latexsubs) +(puthash "\\blacksmiley" "☻" julia-latexsubs) +(puthash "\\sun" "☼" julia-latexsubs) +(puthash "\\rightmoon" "☽" julia-latexsubs) +(puthash "\\leftmoon" "☾" julia-latexsubs) +(puthash "\\mercury" "☿" julia-latexsubs) +(puthash "\\venus" "♀" julia-latexsubs) +(puthash "\\female" "♀" julia-latexsubs) +(puthash "\\male" "♂" julia-latexsubs) +(puthash "\\mars" "♂" julia-latexsubs) +(puthash "\\jupiter" "♃" julia-latexsubs) +(puthash "\\saturn" "♄" julia-latexsubs) +(puthash "\\uranus" "♅" julia-latexsubs) +(puthash "\\neptune" "♆" julia-latexsubs) +(puthash "\\pluto" "♇" julia-latexsubs) +(puthash "\\:aries:" "♈" julia-latexsubs) +(puthash "\\aries" "♈" julia-latexsubs) +(puthash "\\:taurus:" "♉" julia-latexsubs) +(puthash "\\taurus" "♉" julia-latexsubs) +(puthash "\\:gemini:" "♊" julia-latexsubs) +(puthash "\\gemini" "♊" julia-latexsubs) +(puthash "\\:cancer:" "♋" julia-latexsubs) +(puthash "\\cancer" "♋" julia-latexsubs) +(puthash "\\leo" "♌" julia-latexsubs) +(puthash "\\:leo:" "♌" julia-latexsubs) +(puthash "\\:virgo:" "♍" julia-latexsubs) +(puthash "\\virgo" "♍" julia-latexsubs) +(puthash "\\:libra:" "♎" julia-latexsubs) +(puthash "\\libra" "♎" julia-latexsubs) +(puthash "\\scorpio" "♏" julia-latexsubs) +(puthash "\\:scorpius:" "♏" julia-latexsubs) +(puthash "\\sagittarius" "♐" julia-latexsubs) +(puthash "\\:sagittarius:" "♐" julia-latexsubs) +(puthash "\\capricornus" "♑" julia-latexsubs) +(puthash "\\:capricorn:" "♑" julia-latexsubs) +(puthash "\\aquarius" "♒" julia-latexsubs) +(puthash "\\:aquarius:" "♒" julia-latexsubs) +(puthash "\\pisces" "♓" julia-latexsubs) +(puthash "\\:pisces:" "♓" julia-latexsubs) +(puthash "\\spadesuit" "♠" julia-latexsubs) +(puthash "\\:spades:" "♠" julia-latexsubs) +(puthash "\\heartsuit" "♡" julia-latexsubs) +(puthash "\\diamondsuit" "♢" julia-latexsubs) +(puthash "\\:clubs:" "♣" julia-latexsubs) +(puthash "\\clubsuit" "♣" julia-latexsubs) +(puthash "\\varspadesuit" "♤" julia-latexsubs) +(puthash "\\varheartsuit" "♥" julia-latexsubs) +(puthash "\\:hearts:" "♥" julia-latexsubs) +(puthash "\\vardiamondsuit" "♦" julia-latexsubs) +(puthash "\\:diamonds:" "♦" julia-latexsubs) +(puthash "\\varclubsuit" "♧" julia-latexsubs) +(puthash "\\:hotsprings:" "♨" julia-latexsubs) +(puthash "\\quarternote" "♩" julia-latexsubs) +(puthash "\\eighthnote" "♪" julia-latexsubs) +(puthash "\\twonotes" "♫" julia-latexsubs) +(puthash "\\flat" "♭" julia-latexsubs) +(puthash "\\natural" "♮" julia-latexsubs) +(puthash "\\sharp" "♯" julia-latexsubs) +(puthash "\\:recycle:" "♻" julia-latexsubs) +(puthash "\\acidfree" "♾" julia-latexsubs) +(puthash "\\:wheelchair:" "♿" julia-latexsubs) +(puthash "\\dicei" "⚀" julia-latexsubs) +(puthash "\\diceii" "⚁" julia-latexsubs) +(puthash "\\diceiii" "⚂" julia-latexsubs) +(puthash "\\diceiv" "⚃" julia-latexsubs) +(puthash "\\dicev" "⚄" julia-latexsubs) +(puthash "\\dicevi" "⚅" julia-latexsubs) +(puthash "\\circledrightdot" "⚆" julia-latexsubs) +(puthash "\\circledtwodots" "⚇" julia-latexsubs) +(puthash "\\blackcircledrightdot" "⚈" julia-latexsubs) +(puthash "\\blackcircledtwodots" "⚉" julia-latexsubs) +(puthash "\\:anchor:" "⚓" julia-latexsubs) +(puthash "\\:warning:" "⚠" julia-latexsubs) +(puthash "\\:zap:" "⚡" julia-latexsubs) +(puthash "\\hermaphrodite" "⚥" julia-latexsubs) +(puthash "\\:white_circle:" "⚪" julia-latexsubs) +(puthash "\\mdwhtcircle" "⚪" julia-latexsubs) +(puthash "\\mdblkcircle" "⚫" julia-latexsubs) +(puthash "\\:black_circle:" "⚫" julia-latexsubs) +(puthash "\\mdsmwhtcircle" "⚬" julia-latexsubs) +(puthash "\\neuter" "⚲" julia-latexsubs) +(puthash "\\:soccer:" "⚽" julia-latexsubs) +(puthash "\\:baseball:" "⚾" julia-latexsubs) +(puthash "\\:snowman:" "⛄" julia-latexsubs) +(puthash "\\:partly_sunny:" "⛅" julia-latexsubs) +(puthash "\\:ophiuchus:" "⛎" julia-latexsubs) +(puthash "\\:no_entry:" "⛔" julia-latexsubs) +(puthash "\\:church:" "⛪" julia-latexsubs) +(puthash "\\:fountain:" "⛲" julia-latexsubs) +(puthash "\\:golf:" "⛳" julia-latexsubs) +(puthash "\\:boat:" "⛵" julia-latexsubs) +(puthash "\\:tent:" "⛺" julia-latexsubs) +(puthash "\\:fuelpump:" "⛽" julia-latexsubs) +(puthash "\\:scissors:" "✂" julia-latexsubs) +(puthash "\\:white_check_mark:" "✅" julia-latexsubs) +(puthash "\\:airplane:" "✈" julia-latexsubs) +(puthash "\\:email:" "✉" julia-latexsubs) +(puthash "\\:fist:" "✊" julia-latexsubs) +(puthash "\\:hand:" "✋" julia-latexsubs) +(puthash "\\:v:" "✌" julia-latexsubs) +(puthash "\\:pencil2:" "✏" julia-latexsubs) +(puthash "\\:black_nib:" "✒" julia-latexsubs) +(puthash "\\checkmark" "✓" julia-latexsubs) +(puthash "\\:heavy_check_mark:" "✔" julia-latexsubs) +(puthash "\\:heavy_multiplication_x:" "✖" julia-latexsubs) +(puthash "\\maltese" "✠" julia-latexsubs) +(puthash "\\:sparkles:" "✨" julia-latexsubs) +(puthash "\\circledstar" "✪" julia-latexsubs) +(puthash "\\:eight_spoked_asterisk:" "✳" julia-latexsubs) +(puthash "\\:eight_pointed_black_star:" "✴" julia-latexsubs) +(puthash "\\varstar" "✶" julia-latexsubs) +(puthash "\\dingasterisk" "✽" julia-latexsubs) +(puthash "\\:snowflake:" "❄" julia-latexsubs) +(puthash "\\:sparkle:" "❇" julia-latexsubs) +(puthash "\\:x:" "❌" julia-latexsubs) +(puthash "\\:negative_squared_cross_mark:" "❎" julia-latexsubs) +(puthash "\\:question:" "❓" julia-latexsubs) +(puthash "\\:grey_question:" "❔" julia-latexsubs) +(puthash "\\:grey_exclamation:" "❕" julia-latexsubs) +(puthash "\\:exclamation:" "❗" julia-latexsubs) +(puthash "\\:heart:" "❤" julia-latexsubs) +(puthash "\\:heavy_plus_sign:" "➕" julia-latexsubs) +(puthash "\\:heavy_minus_sign:" "➖" julia-latexsubs) +(puthash "\\:heavy_division_sign:" "➗" julia-latexsubs) +(puthash "\\draftingarrow" "➛" julia-latexsubs) +(puthash "\\:arrow_right:" "➡" julia-latexsubs) +(puthash "\\:curly_loop:" "➰" julia-latexsubs) +(puthash "\\:loop:" "➿" julia-latexsubs) +(puthash "\\threedangle" "⟀" julia-latexsubs) +(puthash "\\whiteinwhitetriangle" "⟁" julia-latexsubs) +(puthash "\\perp" "⟂" julia-latexsubs) +(puthash "\\bsolhsub" "⟈" julia-latexsubs) +(puthash "\\suphsol" "⟉" julia-latexsubs) +(puthash "\\wedgedot" "⟑" julia-latexsubs) +(puthash "\\upin" "⟒" julia-latexsubs) +(puthash "\\leftouterjoin" "⟕" julia-latexsubs) +(puthash "\\rightouterjoin" "⟖" julia-latexsubs) +(puthash "\\fullouterjoin" "⟗" julia-latexsubs) +(puthash "\\bigbot" "⟘" julia-latexsubs) +(puthash "\\bigtop" "⟙" julia-latexsubs) +(puthash "\\openbracketleft" "⟦" julia-latexsubs) +(puthash "\\llbracket" "⟦" julia-latexsubs) +(puthash "\\openbracketright" "⟧" julia-latexsubs) +(puthash "\\rrbracket" "⟧" julia-latexsubs) +(puthash "\\langle" "⟨" julia-latexsubs) +(puthash "\\rangle" "⟩" julia-latexsubs) +(puthash "\\UUparrow" "⟰" julia-latexsubs) +(puthash "\\DDownarrow" "⟱" julia-latexsubs) +(puthash "\\longleftarrow" "⟵" julia-latexsubs) +(puthash "\\longrightarrow" "⟶" julia-latexsubs) +(puthash "\\longleftrightarrow" "⟷" julia-latexsubs) +(puthash "\\impliedby" "⟸" julia-latexsubs) +(puthash "\\Longleftarrow" "⟸" julia-latexsubs) +(puthash "\\implies" "⟹" julia-latexsubs) +(puthash "\\Longrightarrow" "⟹" julia-latexsubs) +(puthash "\\iff" "⟺" julia-latexsubs) +(puthash "\\Longleftrightarrow" "⟺" julia-latexsubs) +(puthash "\\longmapsfrom" "⟻" julia-latexsubs) +(puthash "\\longmapsto" "⟼" julia-latexsubs) +(puthash "\\Longmapsfrom" "⟽" julia-latexsubs) +(puthash "\\Longmapsto" "⟾" julia-latexsubs) +(puthash "\\longrightsquigarrow" "⟿" julia-latexsubs) +(puthash "\\nvtwoheadrightarrow" "⤀" julia-latexsubs) +(puthash "\\nVtwoheadrightarrow" "⤁" julia-latexsubs) +(puthash "\\nvLeftarrow" "⤂" julia-latexsubs) +(puthash "\\nvRightarrow" "⤃" julia-latexsubs) +(puthash "\\nvLeftrightarrow" "⤄" julia-latexsubs) +(puthash "\\twoheadmapsto" "⤅" julia-latexsubs) +(puthash "\\Mapsfrom" "⤆" julia-latexsubs) +(puthash "\\Mapsto" "⤇" julia-latexsubs) +(puthash "\\downarrowbarred" "⤈" julia-latexsubs) +(puthash "\\uparrowbarred" "⤉" julia-latexsubs) +(puthash "\\Uuparrow" "⤊" julia-latexsubs) +(puthash "\\Ddownarrow" "⤋" julia-latexsubs) +(puthash "\\leftbkarrow" "⤌" julia-latexsubs) +(puthash "\\bkarow" "⤍" julia-latexsubs) +(puthash "\\leftdbkarrow" "⤎" julia-latexsubs) +(puthash "\\dbkarow" "⤏" julia-latexsubs) +(puthash "\\drbkarrow" "⤐" julia-latexsubs) +(puthash "\\rightdotarrow" "⤑" julia-latexsubs) +(puthash "\\UpArrowBar" "⤒" julia-latexsubs) +(puthash "\\DownArrowBar" "⤓" julia-latexsubs) +(puthash "\\nvrightarrowtail" "⤔" julia-latexsubs) +(puthash "\\nVrightarrowtail" "⤕" julia-latexsubs) +(puthash "\\twoheadrightarrowtail" "⤖" julia-latexsubs) +(puthash "\\nvtwoheadrightarrowtail" "⤗" julia-latexsubs) +(puthash "\\nVtwoheadrightarrowtail" "⤘" julia-latexsubs) +(puthash "\\diamondleftarrow" "⤝" julia-latexsubs) +(puthash "\\rightarrowdiamond" "⤞" julia-latexsubs) +(puthash "\\diamondleftarrowbar" "⤟" julia-latexsubs) +(puthash "\\barrightarrowdiamond" "⤠" julia-latexsubs) +(puthash "\\hksearow" "⤥" julia-latexsubs) +(puthash "\\hkswarow" "⤦" julia-latexsubs) +(puthash "\\tona" "⤧" julia-latexsubs) +(puthash "\\toea" "⤨" julia-latexsubs) +(puthash "\\tosa" "⤩" julia-latexsubs) +(puthash "\\towa" "⤪" julia-latexsubs) +(puthash "\\rdiagovfdiag" "⤫" julia-latexsubs) +(puthash "\\fdiagovrdiag" "⤬" julia-latexsubs) +(puthash "\\seovnearrow" "⤭" julia-latexsubs) +(puthash "\\neovsearrow" "⤮" julia-latexsubs) +(puthash "\\fdiagovnearrow" "⤯" julia-latexsubs) +(puthash "\\rdiagovsearrow" "⤰" julia-latexsubs) +(puthash "\\neovnwarrow" "⤱" julia-latexsubs) +(puthash "\\nwovnearrow" "⤲" julia-latexsubs) +(puthash "\\:arrow_heading_up:" "⤴" julia-latexsubs) +(puthash "\\:arrow_heading_down:" "⤵" julia-latexsubs) +(puthash "\\Rlarr" "⥂" julia-latexsubs) +(puthash "\\rLarr" "⥄" julia-latexsubs) +(puthash "\\rightarrowplus" "⥅" julia-latexsubs) +(puthash "\\leftarrowplus" "⥆" julia-latexsubs) +(puthash "\\rarrx" "⥇" julia-latexsubs) +(puthash "\\leftrightarrowcircle" "⥈" julia-latexsubs) +(puthash "\\twoheaduparrowcircle" "⥉" julia-latexsubs) +(puthash "\\leftrightharpoonupdown" "⥊" julia-latexsubs) +(puthash "\\leftrightharpoondownup" "⥋" julia-latexsubs) +(puthash "\\updownharpoonrightleft" "⥌" julia-latexsubs) +(puthash "\\updownharpoonleftright" "⥍" julia-latexsubs) +(puthash "\\LeftRightVector" "⥎" julia-latexsubs) +(puthash "\\RightUpDownVector" "⥏" julia-latexsubs) +(puthash "\\DownLeftRightVector" "⥐" julia-latexsubs) +(puthash "\\LeftUpDownVector" "⥑" julia-latexsubs) +(puthash "\\LeftVectorBar" "⥒" julia-latexsubs) +(puthash "\\RightVectorBar" "⥓" julia-latexsubs) +(puthash "\\RightUpVectorBar" "⥔" julia-latexsubs) +(puthash "\\RightDownVectorBar" "⥕" julia-latexsubs) +(puthash "\\DownLeftVectorBar" "⥖" julia-latexsubs) +(puthash "\\DownRightVectorBar" "⥗" julia-latexsubs) +(puthash "\\LeftUpVectorBar" "⥘" julia-latexsubs) +(puthash "\\LeftDownVectorBar" "⥙" julia-latexsubs) +(puthash "\\LeftTeeVector" "⥚" julia-latexsubs) +(puthash "\\RightTeeVector" "⥛" julia-latexsubs) +(puthash "\\RightUpTeeVector" "⥜" julia-latexsubs) +(puthash "\\RightDownTeeVector" "⥝" julia-latexsubs) +(puthash "\\DownLeftTeeVector" "⥞" julia-latexsubs) +(puthash "\\DownRightTeeVector" "⥟" julia-latexsubs) +(puthash "\\LeftUpTeeVector" "⥠" julia-latexsubs) +(puthash "\\LeftDownTeeVector" "⥡" julia-latexsubs) +(puthash "\\leftharpoonsupdown" "⥢" julia-latexsubs) +(puthash "\\upharpoonsleftright" "⥣" julia-latexsubs) +(puthash "\\rightharpoonsupdown" "⥤" julia-latexsubs) +(puthash "\\downharpoonsleftright" "⥥" julia-latexsubs) +(puthash "\\leftrightharpoonsup" "⥦" julia-latexsubs) +(puthash "\\leftrightharpoonsdown" "⥧" julia-latexsubs) +(puthash "\\rightleftharpoonsup" "⥨" julia-latexsubs) +(puthash "\\rightleftharpoonsdown" "⥩" julia-latexsubs) +(puthash "\\leftharpoonupdash" "⥪" julia-latexsubs) +(puthash "\\dashleftharpoondown" "⥫" julia-latexsubs) +(puthash "\\rightharpoonupdash" "⥬" julia-latexsubs) +(puthash "\\dashrightharpoondown" "⥭" julia-latexsubs) +(puthash "\\UpEquilibrium" "⥮" julia-latexsubs) +(puthash "\\ReverseUpEquilibrium" "⥯" julia-latexsubs) +(puthash "\\RoundImplies" "⥰" julia-latexsubs) +(puthash "\\Vvert" "⦀" julia-latexsubs) +(puthash "\\Elroang" "⦆" julia-latexsubs) +(puthash "\\ddfnc" "⦙" julia-latexsubs) +(puthash "\\measuredangleleft" "⦛" julia-latexsubs) +(puthash "\\Angle" "⦜" julia-latexsubs) +(puthash "\\rightanglemdot" "⦝" julia-latexsubs) +(puthash "\\angles" "⦞" julia-latexsubs) +(puthash "\\angdnr" "⦟" julia-latexsubs) +(puthash "\\lpargt" "⦠" julia-latexsubs) +(puthash "\\sphericalangleup" "⦡" julia-latexsubs) +(puthash "\\turnangle" "⦢" julia-latexsubs) +(puthash "\\revangle" "⦣" julia-latexsubs) +(puthash "\\angleubar" "⦤" julia-latexsubs) +(puthash "\\revangleubar" "⦥" julia-latexsubs) +(puthash "\\wideangledown" "⦦" julia-latexsubs) +(puthash "\\wideangleup" "⦧" julia-latexsubs) +(puthash "\\measanglerutone" "⦨" julia-latexsubs) +(puthash "\\measanglelutonw" "⦩" julia-latexsubs) +(puthash "\\measanglerdtose" "⦪" julia-latexsubs) +(puthash "\\measangleldtosw" "⦫" julia-latexsubs) +(puthash "\\measangleurtone" "⦬" julia-latexsubs) +(puthash "\\measangleultonw" "⦭" julia-latexsubs) +(puthash "\\measangledrtose" "⦮" julia-latexsubs) +(puthash "\\measangledltosw" "⦯" julia-latexsubs) +(puthash "\\revemptyset" "⦰" julia-latexsubs) +(puthash "\\emptysetobar" "⦱" julia-latexsubs) +(puthash "\\emptysetocirc" "⦲" julia-latexsubs) +(puthash "\\emptysetoarr" "⦳" julia-latexsubs) +(puthash "\\emptysetoarrl" "⦴" julia-latexsubs) +(puthash "\\circledparallel" "⦷" julia-latexsubs) +(puthash "\\obslash" "⦸" julia-latexsubs) +(puthash "\\odotslashdot" "⦼" julia-latexsubs) +(puthash "\\circledwhitebullet" "⦾" julia-latexsubs) +(puthash "\\circledbullet" "⦿" julia-latexsubs) +(puthash "\\olessthan" "⧀" julia-latexsubs) +(puthash "\\ogreaterthan" "⧁" julia-latexsubs) +(puthash "\\boxdiag" "⧄" julia-latexsubs) +(puthash "\\boxbslash" "⧅" julia-latexsubs) +(puthash "\\boxast" "⧆" julia-latexsubs) +(puthash "\\boxcircle" "⧇" julia-latexsubs) +(puthash "\\Lap" "⧊" julia-latexsubs) +(puthash "\\defas" "⧋" julia-latexsubs) +(puthash "\\LeftTriangleBar" "⧏" julia-latexsubs) +(puthash "\\NotLeftTriangleBar" "⧏̸" julia-latexsubs) +(puthash "\\RightTriangleBar" "⧐" julia-latexsubs) +(puthash "\\NotRightTriangleBar" "⧐̸" julia-latexsubs) +(puthash "\\dualmap" "⧟" julia-latexsubs) +(puthash "\\lrtriangleeq" "⧡" julia-latexsubs) +(puthash "\\shuffle" "⧢" julia-latexsubs) +(puthash "\\eparsl" "⧣" julia-latexsubs) +(puthash "\\smeparsl" "⧤" julia-latexsubs) +(puthash "\\eqvparsl" "⧥" julia-latexsubs) +(puthash "\\blacklozenge" "⧫" julia-latexsubs) +(puthash "\\RuleDelayed" "⧴" julia-latexsubs) +(puthash "\\dsol" "⧶" julia-latexsubs) +(puthash "\\rsolbar" "⧷" julia-latexsubs) +(puthash "\\doubleplus" "⧺" julia-latexsubs) +(puthash "\\tripleplus" "⧻" julia-latexsubs) +(puthash "\\bigodot" "⨀" julia-latexsubs) +(puthash "\\bigoplus" "⨁" julia-latexsubs) +(puthash "\\bigotimes" "⨂" julia-latexsubs) +(puthash "\\bigcupdot" "⨃" julia-latexsubs) +(puthash "\\biguplus" "⨄" julia-latexsubs) +(puthash "\\bigsqcap" "⨅" julia-latexsubs) +(puthash "\\bigsqcup" "⨆" julia-latexsubs) +(puthash "\\conjquant" "⨇" julia-latexsubs) +(puthash "\\disjquant" "⨈" julia-latexsubs) +(puthash "\\bigtimes" "⨉" julia-latexsubs) +(puthash "\\modtwosum" "⨊" julia-latexsubs) +(puthash "\\sumint" "⨋" julia-latexsubs) +(puthash "\\iiiint" "⨌" julia-latexsubs) +(puthash "\\intbar" "⨍" julia-latexsubs) +(puthash "\\intBar" "⨎" julia-latexsubs) +(puthash "\\clockoint" "⨏" julia-latexsubs) +(puthash "\\cirfnint" "⨐" julia-latexsubs) +(puthash "\\awint" "⨑" julia-latexsubs) +(puthash "\\rppolint" "⨒" julia-latexsubs) +(puthash "\\scpolint" "⨓" julia-latexsubs) +(puthash "\\npolint" "⨔" julia-latexsubs) +(puthash "\\pointint" "⨕" julia-latexsubs) +(puthash "\\sqrint" "⨖" julia-latexsubs) +(puthash "\\intx" "⨘" julia-latexsubs) +(puthash "\\intcap" "⨙" julia-latexsubs) +(puthash "\\intcup" "⨚" julia-latexsubs) +(puthash "\\upint" "⨛" julia-latexsubs) +(puthash "\\lowint" "⨜" julia-latexsubs) +(puthash "\\join" "⨝" julia-latexsubs) +(puthash "\\Join" "⨝" julia-latexsubs) +(puthash "\\ringplus" "⨢" julia-latexsubs) +(puthash "\\plushat" "⨣" julia-latexsubs) +(puthash "\\simplus" "⨤" julia-latexsubs) +(puthash "\\plusdot" "⨥" julia-latexsubs) +(puthash "\\plussim" "⨦" julia-latexsubs) +(puthash "\\plussubtwo" "⨧" julia-latexsubs) +(puthash "\\plustrif" "⨨" julia-latexsubs) +(puthash "\\commaminus" "⨩" julia-latexsubs) +(puthash "\\minusdot" "⨪" julia-latexsubs) +(puthash "\\minusfdots" "⨫" julia-latexsubs) +(puthash "\\minusrdots" "⨬" julia-latexsubs) +(puthash "\\opluslhrim" "⨭" julia-latexsubs) +(puthash "\\oplusrhrim" "⨮" julia-latexsubs) +(puthash "\\Times" "⨯" julia-latexsubs) +(puthash "\\dottimes" "⨰" julia-latexsubs) +(puthash "\\timesbar" "⨱" julia-latexsubs) +(puthash "\\btimes" "⨲" julia-latexsubs) +(puthash "\\smashtimes" "⨳" julia-latexsubs) +(puthash "\\otimeslhrim" "⨴" julia-latexsubs) +(puthash "\\otimesrhrim" "⨵" julia-latexsubs) +(puthash "\\otimeshat" "⨶" julia-latexsubs) +(puthash "\\Otimes" "⨷" julia-latexsubs) +(puthash "\\odiv" "⨸" julia-latexsubs) +(puthash "\\triangleplus" "⨹" julia-latexsubs) +(puthash "\\triangleminus" "⨺" julia-latexsubs) +(puthash "\\triangletimes" "⨻" julia-latexsubs) +(puthash "\\intprod" "⨼" julia-latexsubs) +(puthash "\\intprodr" "⨽" julia-latexsubs) +(puthash "\\amalg" "⨿" julia-latexsubs) +(puthash "\\capdot" "⩀" julia-latexsubs) +(puthash "\\uminus" "⩁" julia-latexsubs) +(puthash "\\barcup" "⩂" julia-latexsubs) +(puthash "\\barcap" "⩃" julia-latexsubs) +(puthash "\\capwedge" "⩄" julia-latexsubs) +(puthash "\\cupvee" "⩅" julia-latexsubs) +(puthash "\\twocups" "⩊" julia-latexsubs) +(puthash "\\twocaps" "⩋" julia-latexsubs) +(puthash "\\closedvarcup" "⩌" julia-latexsubs) +(puthash "\\closedvarcap" "⩍" julia-latexsubs) +(puthash "\\Sqcap" "⩎" julia-latexsubs) +(puthash "\\Sqcup" "⩏" julia-latexsubs) +(puthash "\\closedvarcupsmashprod" "⩐" julia-latexsubs) +(puthash "\\wedgeodot" "⩑" julia-latexsubs) +(puthash "\\veeodot" "⩒" julia-latexsubs) +(puthash "\\And" "⩓" julia-latexsubs) +(puthash "\\Or" "⩔" julia-latexsubs) +(puthash "\\wedgeonwedge" "⩕" julia-latexsubs) +(puthash "\\ElOr" "⩖" julia-latexsubs) +(puthash "\\bigslopedvee" "⩗" julia-latexsubs) +(puthash "\\bigslopedwedge" "⩘" julia-latexsubs) +(puthash "\\wedgemidvert" "⩚" julia-latexsubs) +(puthash "\\veemidvert" "⩛" julia-latexsubs) +(puthash "\\midbarwedge" "⩜" julia-latexsubs) +(puthash "\\midbarvee" "⩝" julia-latexsubs) +(puthash "\\perspcorrespond" "⩞" julia-latexsubs) +(puthash "\\minhat" "⩟" julia-latexsubs) +(puthash "\\wedgedoublebar" "⩠" julia-latexsubs) +(puthash "\\varveebar" "⩡" julia-latexsubs) +(puthash "\\doublebarvee" "⩢" julia-latexsubs) +(puthash "\\veedoublebar" "⩣" julia-latexsubs) +(puthash "\\eqdot" "⩦" julia-latexsubs) +(puthash "\\dotequiv" "⩧" julia-latexsubs) +(puthash "\\dotsim" "⩪" julia-latexsubs) +(puthash "\\simrdots" "⩫" julia-latexsubs) +(puthash "\\simminussim" "⩬" julia-latexsubs) +(puthash "\\congdot" "⩭" julia-latexsubs) +(puthash "\\asteq" "⩮" julia-latexsubs) +(puthash "\\hatapprox" "⩯" julia-latexsubs) +(puthash "\\approxeqq" "⩰" julia-latexsubs) +(puthash "\\eqqplus" "⩱" julia-latexsubs) +(puthash "\\pluseqq" "⩲" julia-latexsubs) +(puthash "\\eqqsim" "⩳" julia-latexsubs) +(puthash "\\Coloneq" "⩴" julia-latexsubs) +(puthash "\\Equal" "⩵" julia-latexsubs) +(puthash "\\eqeqeq" "⩶" julia-latexsubs) +(puthash "\\ddotseq" "⩷" julia-latexsubs) +(puthash "\\equivDD" "⩸" julia-latexsubs) +(puthash "\\ltcir" "⩹" julia-latexsubs) +(puthash "\\gtcir" "⩺" julia-latexsubs) +(puthash "\\ltquest" "⩻" julia-latexsubs) +(puthash "\\gtquest" "⩼" julia-latexsubs) +(puthash "\\leqslant" "⩽" julia-latexsubs) +(puthash "\\nleqslant" "⩽̸" julia-latexsubs) +(puthash "\\geqslant" "⩾" julia-latexsubs) +(puthash "\\ngeqslant" "⩾̸" julia-latexsubs) +(puthash "\\lesdot" "⩿" julia-latexsubs) +(puthash "\\gesdot" "⪀" julia-latexsubs) +(puthash "\\lesdoto" "⪁" julia-latexsubs) +(puthash "\\gesdoto" "⪂" julia-latexsubs) +(puthash "\\lesdotor" "⪃" julia-latexsubs) +(puthash "\\gesdotol" "⪄" julia-latexsubs) +(puthash "\\lessapprox" "⪅" julia-latexsubs) +(puthash "\\gtrapprox" "⪆" julia-latexsubs) +(puthash "\\lneq" "⪇" julia-latexsubs) +(puthash "\\gneq" "⪈" julia-latexsubs) +(puthash "\\lnapprox" "⪉" julia-latexsubs) +(puthash "\\gnapprox" "⪊" julia-latexsubs) +(puthash "\\lesseqqgtr" "⪋" julia-latexsubs) +(puthash "\\gtreqqless" "⪌" julia-latexsubs) +(puthash "\\lsime" "⪍" julia-latexsubs) +(puthash "\\gsime" "⪎" julia-latexsubs) +(puthash "\\lsimg" "⪏" julia-latexsubs) +(puthash "\\gsiml" "⪐" julia-latexsubs) +(puthash "\\lgE" "⪑" julia-latexsubs) +(puthash "\\glE" "⪒" julia-latexsubs) +(puthash "\\lesges" "⪓" julia-latexsubs) +(puthash "\\gesles" "⪔" julia-latexsubs) +(puthash "\\eqslantless" "⪕" julia-latexsubs) +(puthash "\\eqslantgtr" "⪖" julia-latexsubs) +(puthash "\\elsdot" "⪗" julia-latexsubs) +(puthash "\\egsdot" "⪘" julia-latexsubs) +(puthash "\\eqqless" "⪙" julia-latexsubs) +(puthash "\\eqqgtr" "⪚" julia-latexsubs) +(puthash "\\eqqslantless" "⪛" julia-latexsubs) +(puthash "\\eqqslantgtr" "⪜" julia-latexsubs) +(puthash "\\simless" "⪝" julia-latexsubs) +(puthash "\\simgtr" "⪞" julia-latexsubs) +(puthash "\\simlE" "⪟" julia-latexsubs) +(puthash "\\simgE" "⪠" julia-latexsubs) +(puthash "\\NestedLessLess" "⪡" julia-latexsubs) +(puthash "\\NotNestedLessLess" "⪡̸" julia-latexsubs) +(puthash "\\NestedGreaterGreater" "⪢" julia-latexsubs) +(puthash "\\NotNestedGreaterGreater" "⪢̸" julia-latexsubs) +(puthash "\\partialmeetcontraction" "⪣" julia-latexsubs) +(puthash "\\glj" "⪤" julia-latexsubs) +(puthash "\\gla" "⪥" julia-latexsubs) +(puthash "\\ltcc" "⪦" julia-latexsubs) +(puthash "\\gtcc" "⪧" julia-latexsubs) +(puthash "\\lescc" "⪨" julia-latexsubs) +(puthash "\\gescc" "⪩" julia-latexsubs) +(puthash "\\smt" "⪪" julia-latexsubs) +(puthash "\\lat" "⪫" julia-latexsubs) +(puthash "\\smte" "⪬" julia-latexsubs) +(puthash "\\late" "⪭" julia-latexsubs) +(puthash "\\bumpeqq" "⪮" julia-latexsubs) +(puthash "\\preceq" "⪯" julia-latexsubs) +(puthash "\\npreceq" "⪯̸" julia-latexsubs) +(puthash "\\succeq" "⪰" julia-latexsubs) +(puthash "\\nsucceq" "⪰̸" julia-latexsubs) +(puthash "\\precneq" "⪱" julia-latexsubs) +(puthash "\\succneq" "⪲" julia-latexsubs) +(puthash "\\preceqq" "⪳" julia-latexsubs) +(puthash "\\succeqq" "⪴" julia-latexsubs) +(puthash "\\precneqq" "⪵" julia-latexsubs) +(puthash "\\succneqq" "⪶" julia-latexsubs) +(puthash "\\precapprox" "⪷" julia-latexsubs) +(puthash "\\succapprox" "⪸" julia-latexsubs) +(puthash "\\precnapprox" "⪹" julia-latexsubs) +(puthash "\\succnapprox" "⪺" julia-latexsubs) +(puthash "\\Prec" "⪻" julia-latexsubs) +(puthash "\\Succ" "⪼" julia-latexsubs) +(puthash "\\subsetdot" "⪽" julia-latexsubs) +(puthash "\\supsetdot" "⪾" julia-latexsubs) +(puthash "\\subsetplus" "⪿" julia-latexsubs) +(puthash "\\supsetplus" "⫀" julia-latexsubs) +(puthash "\\submult" "⫁" julia-latexsubs) +(puthash "\\supmult" "⫂" julia-latexsubs) +(puthash "\\subedot" "⫃" julia-latexsubs) +(puthash "\\supedot" "⫄" julia-latexsubs) +(puthash "\\subseteqq" "⫅" julia-latexsubs) +(puthash "\\nsubseteqq" "⫅̸" julia-latexsubs) +(puthash "\\supseteqq" "⫆" julia-latexsubs) +(puthash "\\nsupseteqq" "⫆̸" julia-latexsubs) +(puthash "\\subsim" "⫇" julia-latexsubs) +(puthash "\\supsim" "⫈" julia-latexsubs) +(puthash "\\subsetapprox" "⫉" julia-latexsubs) +(puthash "\\supsetapprox" "⫊" julia-latexsubs) +(puthash "\\subsetneqq" "⫋" julia-latexsubs) +(puthash "\\supsetneqq" "⫌" julia-latexsubs) +(puthash "\\lsqhook" "⫍" julia-latexsubs) +(puthash "\\rsqhook" "⫎" julia-latexsubs) +(puthash "\\csub" "⫏" julia-latexsubs) +(puthash "\\csup" "⫐" julia-latexsubs) +(puthash "\\csube" "⫑" julia-latexsubs) +(puthash "\\csupe" "⫒" julia-latexsubs) +(puthash "\\subsup" "⫓" julia-latexsubs) +(puthash "\\supsub" "⫔" julia-latexsubs) +(puthash "\\subsub" "⫕" julia-latexsubs) +(puthash "\\supsup" "⫖" julia-latexsubs) +(puthash "\\suphsub" "⫗" julia-latexsubs) +(puthash "\\supdsub" "⫘" julia-latexsubs) +(puthash "\\forkv" "⫙" julia-latexsubs) +(puthash "\\mlcp" "⫛" julia-latexsubs) +(puthash "\\forks" "⫝̸" julia-latexsubs) +(puthash "\\forksnot" "⫝" julia-latexsubs) +(puthash "\\dashV" "⫣" julia-latexsubs) +(puthash "\\Dashv" "⫤" julia-latexsubs) +(puthash "\\interleave" "⫴" julia-latexsubs) +(puthash "\\tdcol" "⫶" julia-latexsubs) +(puthash "\\lllnest" "⫷" julia-latexsubs) +(puthash "\\gggnest" "⫸" julia-latexsubs) +(puthash "\\leqqslant" "⫹" julia-latexsubs) +(puthash "\\geqqslant" "⫺" julia-latexsubs) +(puthash "\\:arrow_left:" "⬅" julia-latexsubs) +(puthash "\\:arrow_up:" "⬆" julia-latexsubs) +(puthash "\\:arrow_down:" "⬇" julia-latexsubs) +(puthash "\\squaretopblack" "⬒" julia-latexsubs) +(puthash "\\squarebotblack" "⬓" julia-latexsubs) +(puthash "\\squareurblack" "⬔" julia-latexsubs) +(puthash "\\squarellblack" "⬕" julia-latexsubs) +(puthash "\\diamondleftblack" "⬖" julia-latexsubs) +(puthash "\\diamondrightblack" "⬗" julia-latexsubs) +(puthash "\\diamondtopblack" "⬘" julia-latexsubs) +(puthash "\\diamondbotblack" "⬙" julia-latexsubs) +(puthash "\\dottedsquare" "⬚" julia-latexsubs) +(puthash "\\lgblksquare" "⬛" julia-latexsubs) +(puthash "\\:black_large_square:" "⬛" julia-latexsubs) +(puthash "\\lgwhtsquare" "⬜" julia-latexsubs) +(puthash "\\:white_large_square:" "⬜" julia-latexsubs) +(puthash "\\vysmblksquare" "⬝" julia-latexsubs) +(puthash "\\vysmwhtsquare" "⬞" julia-latexsubs) +(puthash "\\pentagonblack" "⬟" julia-latexsubs) +(puthash "\\pentagon" "⬠" julia-latexsubs) +(puthash "\\varhexagon" "⬡" julia-latexsubs) +(puthash "\\varhexagonblack" "⬢" julia-latexsubs) +(puthash "\\hexagonblack" "⬣" julia-latexsubs) +(puthash "\\lgblkcircle" "⬤" julia-latexsubs) +(puthash "\\mdblkdiamond" "⬥" julia-latexsubs) +(puthash "\\mdwhtdiamond" "⬦" julia-latexsubs) +(puthash "\\mdblklozenge" "⬧" julia-latexsubs) +(puthash "\\mdwhtlozenge" "⬨" julia-latexsubs) +(puthash "\\smblkdiamond" "⬩" julia-latexsubs) +(puthash "\\smblklozenge" "⬪" julia-latexsubs) +(puthash "\\smwhtlozenge" "⬫" julia-latexsubs) +(puthash "\\blkhorzoval" "⬬" julia-latexsubs) +(puthash "\\whthorzoval" "⬭" julia-latexsubs) +(puthash "\\blkvertoval" "⬮" julia-latexsubs) +(puthash "\\whtvertoval" "⬯" julia-latexsubs) +(puthash "\\circleonleftarrow" "⬰" julia-latexsubs) +(puthash "\\leftthreearrows" "⬱" julia-latexsubs) +(puthash "\\leftarrowonoplus" "⬲" julia-latexsubs) +(puthash "\\longleftsquigarrow" "⬳" julia-latexsubs) +(puthash "\\nvtwoheadleftarrow" "⬴" julia-latexsubs) +(puthash "\\nVtwoheadleftarrow" "⬵" julia-latexsubs) +(puthash "\\twoheadmapsfrom" "⬶" julia-latexsubs) +(puthash "\\twoheadleftdbkarrow" "⬷" julia-latexsubs) +(puthash "\\leftdotarrow" "⬸" julia-latexsubs) +(puthash "\\nvleftarrowtail" "⬹" julia-latexsubs) +(puthash "\\nVleftarrowtail" "⬺" julia-latexsubs) +(puthash "\\twoheadleftarrowtail" "⬻" julia-latexsubs) +(puthash "\\nvtwoheadleftarrowtail" "⬼" julia-latexsubs) +(puthash "\\nVtwoheadleftarrowtail" "⬽" julia-latexsubs) +(puthash "\\leftarrowx" "⬾" julia-latexsubs) +(puthash "\\leftcurvedarrow" "⬿" julia-latexsubs) +(puthash "\\equalleftarrow" "⭀" julia-latexsubs) +(puthash "\\bsimilarleftarrow" "⭁" julia-latexsubs) +(puthash "\\leftarrowbackapprox" "⭂" julia-latexsubs) +(puthash "\\rightarrowgtr" "⭃" julia-latexsubs) +(puthash "\\rightarrowsupset" "⭄" julia-latexsubs) +(puthash "\\LLeftarrow" "⭅" julia-latexsubs) +(puthash "\\RRightarrow" "⭆" julia-latexsubs) +(puthash "\\bsimilarrightarrow" "⭇" julia-latexsubs) +(puthash "\\rightarrowbackapprox" "⭈" julia-latexsubs) +(puthash "\\similarleftarrow" "⭉" julia-latexsubs) +(puthash "\\leftarrowapprox" "⭊" julia-latexsubs) +(puthash "\\leftarrowbsimilar" "⭋" julia-latexsubs) +(puthash "\\rightarrowbsimilar" "⭌" julia-latexsubs) +(puthash "\\:star:" "⭐" julia-latexsubs) +(puthash "\\medwhitestar" "⭐" julia-latexsubs) +(puthash "\\medblackstar" "⭑" julia-latexsubs) +(puthash "\\smwhitestar" "⭒" julia-latexsubs) +(puthash "\\rightpentagonblack" "⭓" julia-latexsubs) +(puthash "\\rightpentagon" "⭔" julia-latexsubs) +(puthash "\\:o:" "⭕" julia-latexsubs) +(puthash "\\_j" "ⱼ" julia-latexsubs) +(puthash "\\^V" "ⱽ" julia-latexsubs) +(puthash "\\postalmark" "〒" julia-latexsubs) +(puthash "\\:wavy_dash:" "〰" julia-latexsubs) +(puthash "\\:part_alternation_mark:" "〽" julia-latexsubs) +(puthash "\\:congratulations:" "㊗" julia-latexsubs) +(puthash "\\:secret:" "㊙" julia-latexsubs) +(puthash "\\bfA" "𝐀" julia-latexsubs) +(puthash "\\bfB" "𝐁" julia-latexsubs) +(puthash "\\bfC" "𝐂" julia-latexsubs) +(puthash "\\bfD" "𝐃" julia-latexsubs) +(puthash "\\bfE" "𝐄" julia-latexsubs) +(puthash "\\bfF" "𝐅" julia-latexsubs) +(puthash "\\bfG" "𝐆" julia-latexsubs) +(puthash "\\bfH" "𝐇" julia-latexsubs) +(puthash "\\bfI" "𝐈" julia-latexsubs) +(puthash "\\bfJ" "𝐉" julia-latexsubs) +(puthash "\\bfK" "𝐊" julia-latexsubs) +(puthash "\\bfL" "𝐋" julia-latexsubs) +(puthash "\\bfM" "𝐌" julia-latexsubs) +(puthash "\\bfN" "𝐍" julia-latexsubs) +(puthash "\\bfO" "𝐎" julia-latexsubs) +(puthash "\\bfP" "𝐏" julia-latexsubs) +(puthash "\\bfQ" "𝐐" julia-latexsubs) +(puthash "\\bfR" "𝐑" julia-latexsubs) +(puthash "\\bfS" "𝐒" julia-latexsubs) +(puthash "\\bfT" "𝐓" julia-latexsubs) +(puthash "\\bfU" "𝐔" julia-latexsubs) +(puthash "\\bfV" "𝐕" julia-latexsubs) +(puthash "\\bfW" "𝐖" julia-latexsubs) +(puthash "\\bfX" "𝐗" julia-latexsubs) +(puthash "\\bfY" "𝐘" julia-latexsubs) +(puthash "\\bfZ" "𝐙" julia-latexsubs) +(puthash "\\bfa" "𝐚" julia-latexsubs) +(puthash "\\bfb" "𝐛" julia-latexsubs) +(puthash "\\bfc" "𝐜" julia-latexsubs) +(puthash "\\bfd" "𝐝" julia-latexsubs) +(puthash "\\bfe" "𝐞" julia-latexsubs) +(puthash "\\bff" "𝐟" julia-latexsubs) +(puthash "\\bfg" "𝐠" julia-latexsubs) +(puthash "\\bfh" "𝐡" julia-latexsubs) +(puthash "\\bfi" "𝐢" julia-latexsubs) +(puthash "\\bfj" "𝐣" julia-latexsubs) +(puthash "\\bfk" "𝐤" julia-latexsubs) +(puthash "\\bfl" "𝐥" julia-latexsubs) +(puthash "\\bfm" "𝐦" julia-latexsubs) +(puthash "\\bfn" "𝐧" julia-latexsubs) +(puthash "\\bfo" "𝐨" julia-latexsubs) +(puthash "\\bfp" "𝐩" julia-latexsubs) +(puthash "\\bfq" "𝐪" julia-latexsubs) +(puthash "\\bfr" "𝐫" julia-latexsubs) +(puthash "\\bfs" "𝐬" julia-latexsubs) +(puthash "\\bft" "𝐭" julia-latexsubs) +(puthash "\\bfu" "𝐮" julia-latexsubs) +(puthash "\\bfv" "𝐯" julia-latexsubs) +(puthash "\\bfw" "𝐰" julia-latexsubs) +(puthash "\\bfx" "𝐱" julia-latexsubs) +(puthash "\\bfy" "𝐲" julia-latexsubs) +(puthash "\\bfz" "𝐳" julia-latexsubs) +(puthash "\\itA" "𝐴" julia-latexsubs) +(puthash "\\itB" "𝐵" julia-latexsubs) +(puthash "\\itC" "𝐶" julia-latexsubs) +(puthash "\\itD" "𝐷" julia-latexsubs) +(puthash "\\itE" "𝐸" julia-latexsubs) +(puthash "\\itF" "𝐹" julia-latexsubs) +(puthash "\\itG" "𝐺" julia-latexsubs) +(puthash "\\itH" "𝐻" julia-latexsubs) +(puthash "\\itI" "𝐼" julia-latexsubs) +(puthash "\\itJ" "𝐽" julia-latexsubs) +(puthash "\\itK" "𝐾" julia-latexsubs) +(puthash "\\itL" "𝐿" julia-latexsubs) +(puthash "\\itM" "𝑀" julia-latexsubs) +(puthash "\\itN" "𝑁" julia-latexsubs) +(puthash "\\itO" "𝑂" julia-latexsubs) +(puthash "\\itP" "𝑃" julia-latexsubs) +(puthash "\\itQ" "𝑄" julia-latexsubs) +(puthash "\\itR" "𝑅" julia-latexsubs) +(puthash "\\itS" "𝑆" julia-latexsubs) +(puthash "\\itT" "𝑇" julia-latexsubs) +(puthash "\\itU" "𝑈" julia-latexsubs) +(puthash "\\itV" "𝑉" julia-latexsubs) +(puthash "\\itW" "𝑊" julia-latexsubs) +(puthash "\\itX" "𝑋" julia-latexsubs) +(puthash "\\itY" "𝑌" julia-latexsubs) +(puthash "\\itZ" "𝑍" julia-latexsubs) +(puthash "\\ita" "𝑎" julia-latexsubs) +(puthash "\\itb" "𝑏" julia-latexsubs) +(puthash "\\itc" "𝑐" julia-latexsubs) +(puthash "\\itd" "𝑑" julia-latexsubs) +(puthash "\\ite" "𝑒" julia-latexsubs) +(puthash "\\itf" "𝑓" julia-latexsubs) +(puthash "\\itg" "𝑔" julia-latexsubs) +(puthash "\\iti" "𝑖" julia-latexsubs) +(puthash "\\itj" "𝑗" julia-latexsubs) +(puthash "\\itk" "𝑘" julia-latexsubs) +(puthash "\\itl" "𝑙" julia-latexsubs) +(puthash "\\itm" "𝑚" julia-latexsubs) +(puthash "\\itn" "𝑛" julia-latexsubs) +(puthash "\\ito" "𝑜" julia-latexsubs) +(puthash "\\itp" "𝑝" julia-latexsubs) +(puthash "\\itq" "𝑞" julia-latexsubs) +(puthash "\\itr" "𝑟" julia-latexsubs) +(puthash "\\its" "𝑠" julia-latexsubs) +(puthash "\\itt" "𝑡" julia-latexsubs) +(puthash "\\itu" "𝑢" julia-latexsubs) +(puthash "\\itv" "𝑣" julia-latexsubs) +(puthash "\\itw" "𝑤" julia-latexsubs) +(puthash "\\itx" "𝑥" julia-latexsubs) +(puthash "\\ity" "𝑦" julia-latexsubs) +(puthash "\\itz" "𝑧" julia-latexsubs) +(puthash "\\biA" "𝑨" julia-latexsubs) +(puthash "\\biB" "𝑩" julia-latexsubs) +(puthash "\\biC" "𝑪" julia-latexsubs) +(puthash "\\biD" "𝑫" julia-latexsubs) +(puthash "\\biE" "𝑬" julia-latexsubs) +(puthash "\\biF" "𝑭" julia-latexsubs) +(puthash "\\biG" "𝑮" julia-latexsubs) +(puthash "\\biH" "𝑯" julia-latexsubs) +(puthash "\\biI" "𝑰" julia-latexsubs) +(puthash "\\biJ" "𝑱" julia-latexsubs) +(puthash "\\biK" "𝑲" julia-latexsubs) +(puthash "\\biL" "𝑳" julia-latexsubs) +(puthash "\\biM" "𝑴" julia-latexsubs) +(puthash "\\biN" "𝑵" julia-latexsubs) +(puthash "\\biO" "𝑶" julia-latexsubs) +(puthash "\\biP" "𝑷" julia-latexsubs) +(puthash "\\biQ" "𝑸" julia-latexsubs) +(puthash "\\biR" "𝑹" julia-latexsubs) +(puthash "\\biS" "𝑺" julia-latexsubs) +(puthash "\\biT" "𝑻" julia-latexsubs) +(puthash "\\biU" "𝑼" julia-latexsubs) +(puthash "\\biV" "𝑽" julia-latexsubs) +(puthash "\\biW" "𝑾" julia-latexsubs) +(puthash "\\biX" "𝑿" julia-latexsubs) +(puthash "\\biY" "𝒀" julia-latexsubs) +(puthash "\\biZ" "𝒁" julia-latexsubs) +(puthash "\\bia" "𝒂" julia-latexsubs) +(puthash "\\bib" "𝒃" julia-latexsubs) +(puthash "\\bic" "𝒄" julia-latexsubs) +(puthash "\\bid" "𝒅" julia-latexsubs) +(puthash "\\bie" "𝒆" julia-latexsubs) +(puthash "\\bif" "𝒇" julia-latexsubs) +(puthash "\\big" "𝒈" julia-latexsubs) +(puthash "\\bih" "𝒉" julia-latexsubs) +(puthash "\\bii" "𝒊" julia-latexsubs) +(puthash "\\bij" "𝒋" julia-latexsubs) +(puthash "\\bik" "𝒌" julia-latexsubs) +(puthash "\\bil" "𝒍" julia-latexsubs) +(puthash "\\bim" "𝒎" julia-latexsubs) +(puthash "\\bin" "𝒏" julia-latexsubs) +(puthash "\\bio" "𝒐" julia-latexsubs) +(puthash "\\bip" "𝒑" julia-latexsubs) +(puthash "\\biq" "𝒒" julia-latexsubs) +(puthash "\\bir" "𝒓" julia-latexsubs) +(puthash "\\bis" "𝒔" julia-latexsubs) +(puthash "\\bit" "𝒕" julia-latexsubs) +(puthash "\\biu" "𝒖" julia-latexsubs) +(puthash "\\biv" "𝒗" julia-latexsubs) +(puthash "\\biw" "𝒘" julia-latexsubs) +(puthash "\\bix" "𝒙" julia-latexsubs) +(puthash "\\biy" "𝒚" julia-latexsubs) +(puthash "\\biz" "𝒛" julia-latexsubs) +(puthash "\\scrA" "𝒜" julia-latexsubs) +(puthash "\\scrC" "𝒞" julia-latexsubs) +(puthash "\\scrD" "𝒟" julia-latexsubs) +(puthash "\\scrG" "𝒢" julia-latexsubs) +(puthash "\\scrJ" "𝒥" julia-latexsubs) +(puthash "\\scrK" "𝒦" julia-latexsubs) +(puthash "\\scrN" "𝒩" julia-latexsubs) +(puthash "\\scrO" "𝒪" julia-latexsubs) +(puthash "\\scrP" "𝒫" julia-latexsubs) +(puthash "\\scrQ" "𝒬" julia-latexsubs) +(puthash "\\scrS" "𝒮" julia-latexsubs) +(puthash "\\scrT" "𝒯" julia-latexsubs) +(puthash "\\scrU" "𝒰" julia-latexsubs) +(puthash "\\scrV" "𝒱" julia-latexsubs) +(puthash "\\scrW" "𝒲" julia-latexsubs) +(puthash "\\scrX" "𝒳" julia-latexsubs) +(puthash "\\scrY" "𝒴" julia-latexsubs) +(puthash "\\scrZ" "𝒵" julia-latexsubs) +(puthash "\\scra" "𝒶" julia-latexsubs) +(puthash "\\scrb" "𝒷" julia-latexsubs) +(puthash "\\scrc" "𝒸" julia-latexsubs) +(puthash "\\scrd" "𝒹" julia-latexsubs) +(puthash "\\scrf" "𝒻" julia-latexsubs) +(puthash "\\scrh" "𝒽" julia-latexsubs) +(puthash "\\scri" "𝒾" julia-latexsubs) +(puthash "\\scrj" "𝒿" julia-latexsubs) +(puthash "\\scrk" "𝓀" julia-latexsubs) +(puthash "\\scrl" "𝓁" julia-latexsubs) +(puthash "\\scrm" "𝓂" julia-latexsubs) +(puthash "\\scrn" "𝓃" julia-latexsubs) +(puthash "\\scrp" "𝓅" julia-latexsubs) +(puthash "\\scrq" "𝓆" julia-latexsubs) +(puthash "\\scrr" "𝓇" julia-latexsubs) +(puthash "\\scrs" "𝓈" julia-latexsubs) +(puthash "\\scrt" "𝓉" julia-latexsubs) +(puthash "\\scru" "𝓊" julia-latexsubs) +(puthash "\\scrv" "𝓋" julia-latexsubs) +(puthash "\\scrw" "𝓌" julia-latexsubs) +(puthash "\\scrx" "𝓍" julia-latexsubs) +(puthash "\\scry" "𝓎" julia-latexsubs) +(puthash "\\scrz" "𝓏" julia-latexsubs) +(puthash "\\bscrA" "𝓐" julia-latexsubs) +(puthash "\\bscrB" "𝓑" julia-latexsubs) +(puthash "\\bscrC" "𝓒" julia-latexsubs) +(puthash "\\bscrD" "𝓓" julia-latexsubs) +(puthash "\\bscrE" "𝓔" julia-latexsubs) +(puthash "\\bscrF" "𝓕" julia-latexsubs) +(puthash "\\bscrG" "𝓖" julia-latexsubs) +(puthash "\\bscrH" "𝓗" julia-latexsubs) +(puthash "\\bscrI" "𝓘" julia-latexsubs) +(puthash "\\bscrJ" "𝓙" julia-latexsubs) +(puthash "\\bscrK" "𝓚" julia-latexsubs) +(puthash "\\bscrL" "𝓛" julia-latexsubs) +(puthash "\\bscrM" "𝓜" julia-latexsubs) +(puthash "\\bscrN" "𝓝" julia-latexsubs) +(puthash "\\bscrO" "𝓞" julia-latexsubs) +(puthash "\\bscrP" "𝓟" julia-latexsubs) +(puthash "\\bscrQ" "𝓠" julia-latexsubs) +(puthash "\\bscrR" "𝓡" julia-latexsubs) +(puthash "\\bscrS" "𝓢" julia-latexsubs) +(puthash "\\bscrT" "𝓣" julia-latexsubs) +(puthash "\\bscrU" "𝓤" julia-latexsubs) +(puthash "\\bscrV" "𝓥" julia-latexsubs) +(puthash "\\bscrW" "𝓦" julia-latexsubs) +(puthash "\\bscrX" "𝓧" julia-latexsubs) +(puthash "\\bscrY" "𝓨" julia-latexsubs) +(puthash "\\bscrZ" "𝓩" julia-latexsubs) +(puthash "\\bscra" "𝓪" julia-latexsubs) +(puthash "\\bscrb" "𝓫" julia-latexsubs) +(puthash "\\bscrc" "𝓬" julia-latexsubs) +(puthash "\\bscrd" "𝓭" julia-latexsubs) +(puthash "\\bscre" "𝓮" julia-latexsubs) +(puthash "\\bscrf" "𝓯" julia-latexsubs) +(puthash "\\bscrg" "𝓰" julia-latexsubs) +(puthash "\\bscrh" "𝓱" julia-latexsubs) +(puthash "\\bscri" "𝓲" julia-latexsubs) +(puthash "\\bscrj" "𝓳" julia-latexsubs) +(puthash "\\bscrk" "𝓴" julia-latexsubs) +(puthash "\\bscrl" "𝓵" julia-latexsubs) +(puthash "\\bscrm" "𝓶" julia-latexsubs) +(puthash "\\bscrn" "𝓷" julia-latexsubs) +(puthash "\\bscro" "𝓸" julia-latexsubs) +(puthash "\\bscrp" "𝓹" julia-latexsubs) +(puthash "\\bscrq" "𝓺" julia-latexsubs) +(puthash "\\bscrr" "𝓻" julia-latexsubs) +(puthash "\\bscrs" "𝓼" julia-latexsubs) +(puthash "\\bscrt" "𝓽" julia-latexsubs) +(puthash "\\bscru" "𝓾" julia-latexsubs) +(puthash "\\bscrv" "𝓿" julia-latexsubs) +(puthash "\\bscrw" "𝔀" julia-latexsubs) +(puthash "\\bscrx" "𝔁" julia-latexsubs) +(puthash "\\bscry" "𝔂" julia-latexsubs) +(puthash "\\bscrz" "𝔃" julia-latexsubs) +(puthash "\\frakA" "𝔄" julia-latexsubs) +(puthash "\\frakB" "𝔅" julia-latexsubs) +(puthash "\\frakD" "𝔇" julia-latexsubs) +(puthash "\\frakE" "𝔈" julia-latexsubs) +(puthash "\\frakF" "𝔉" julia-latexsubs) +(puthash "\\frakG" "𝔊" julia-latexsubs) +(puthash "\\frakJ" "𝔍" julia-latexsubs) +(puthash "\\frakK" "𝔎" julia-latexsubs) +(puthash "\\frakL" "𝔏" julia-latexsubs) +(puthash "\\frakM" "𝔐" julia-latexsubs) +(puthash "\\frakN" "𝔑" julia-latexsubs) +(puthash "\\frakO" "𝔒" julia-latexsubs) +(puthash "\\frakP" "𝔓" julia-latexsubs) +(puthash "\\frakQ" "𝔔" julia-latexsubs) +(puthash "\\frakS" "𝔖" julia-latexsubs) +(puthash "\\frakT" "𝔗" julia-latexsubs) +(puthash "\\frakU" "𝔘" julia-latexsubs) +(puthash "\\frakV" "𝔙" julia-latexsubs) +(puthash "\\frakW" "𝔚" julia-latexsubs) +(puthash "\\frakX" "𝔛" julia-latexsubs) +(puthash "\\frakY" "𝔜" julia-latexsubs) +(puthash "\\fraka" "𝔞" julia-latexsubs) +(puthash "\\frakb" "𝔟" julia-latexsubs) +(puthash "\\frakc" "𝔠" julia-latexsubs) +(puthash "\\frakd" "𝔡" julia-latexsubs) +(puthash "\\frake" "𝔢" julia-latexsubs) +(puthash "\\frakf" "𝔣" julia-latexsubs) +(puthash "\\frakg" "𝔤" julia-latexsubs) +(puthash "\\frakh" "𝔥" julia-latexsubs) +(puthash "\\fraki" "𝔦" julia-latexsubs) +(puthash "\\frakj" "𝔧" julia-latexsubs) +(puthash "\\frakk" "𝔨" julia-latexsubs) +(puthash "\\frakl" "𝔩" julia-latexsubs) +(puthash "\\frakm" "𝔪" julia-latexsubs) +(puthash "\\frakn" "𝔫" julia-latexsubs) +(puthash "\\frako" "𝔬" julia-latexsubs) +(puthash "\\frakp" "𝔭" julia-latexsubs) +(puthash "\\frakq" "𝔮" julia-latexsubs) +(puthash "\\frakr" "𝔯" julia-latexsubs) +(puthash "\\fraks" "𝔰" julia-latexsubs) +(puthash "\\frakt" "𝔱" julia-latexsubs) +(puthash "\\fraku" "𝔲" julia-latexsubs) +(puthash "\\frakv" "𝔳" julia-latexsubs) +(puthash "\\frakw" "𝔴" julia-latexsubs) +(puthash "\\frakx" "𝔵" julia-latexsubs) +(puthash "\\fraky" "𝔶" julia-latexsubs) +(puthash "\\frakz" "𝔷" julia-latexsubs) +(puthash "\\bbA" "𝔸" julia-latexsubs) +(puthash "\\bbB" "𝔹" julia-latexsubs) +(puthash "\\bbD" "𝔻" julia-latexsubs) +(puthash "\\bbE" "𝔼" julia-latexsubs) +(puthash "\\bbF" "𝔽" julia-latexsubs) +(puthash "\\bbG" "𝔾" julia-latexsubs) +(puthash "\\bbI" "𝕀" julia-latexsubs) +(puthash "\\bbJ" "𝕁" julia-latexsubs) +(puthash "\\bbK" "𝕂" julia-latexsubs) +(puthash "\\bbL" "𝕃" julia-latexsubs) +(puthash "\\bbM" "𝕄" julia-latexsubs) +(puthash "\\bbO" "𝕆" julia-latexsubs) +(puthash "\\bbS" "𝕊" julia-latexsubs) +(puthash "\\bbT" "𝕋" julia-latexsubs) +(puthash "\\bbU" "𝕌" julia-latexsubs) +(puthash "\\bbV" "𝕍" julia-latexsubs) +(puthash "\\bbW" "𝕎" julia-latexsubs) +(puthash "\\bbX" "𝕏" julia-latexsubs) +(puthash "\\bbY" "𝕐" julia-latexsubs) +(puthash "\\bba" "𝕒" julia-latexsubs) +(puthash "\\bbb" "𝕓" julia-latexsubs) +(puthash "\\bbc" "𝕔" julia-latexsubs) +(puthash "\\bbd" "𝕕" julia-latexsubs) +(puthash "\\bbe" "𝕖" julia-latexsubs) +(puthash "\\bbf" "𝕗" julia-latexsubs) +(puthash "\\bbg" "𝕘" julia-latexsubs) +(puthash "\\bbh" "𝕙" julia-latexsubs) +(puthash "\\bbi" "𝕚" julia-latexsubs) +(puthash "\\bbj" "𝕛" julia-latexsubs) +(puthash "\\bbk" "𝕜" julia-latexsubs) +(puthash "\\bbl" "𝕝" julia-latexsubs) +(puthash "\\bbm" "𝕞" julia-latexsubs) +(puthash "\\bbn" "𝕟" julia-latexsubs) +(puthash "\\bbo" "𝕠" julia-latexsubs) +(puthash "\\bbp" "𝕡" julia-latexsubs) +(puthash "\\bbq" "𝕢" julia-latexsubs) +(puthash "\\bbr" "𝕣" julia-latexsubs) +(puthash "\\bbs" "𝕤" julia-latexsubs) +(puthash "\\bbt" "𝕥" julia-latexsubs) +(puthash "\\bbu" "𝕦" julia-latexsubs) +(puthash "\\bbv" "𝕧" julia-latexsubs) +(puthash "\\bbw" "𝕨" julia-latexsubs) +(puthash "\\bbx" "𝕩" julia-latexsubs) +(puthash "\\bby" "𝕪" julia-latexsubs) +(puthash "\\bbz" "𝕫" julia-latexsubs) +(puthash "\\bfrakA" "𝕬" julia-latexsubs) +(puthash "\\bfrakB" "𝕭" julia-latexsubs) +(puthash "\\bfrakC" "𝕮" julia-latexsubs) +(puthash "\\bfrakD" "𝕯" julia-latexsubs) +(puthash "\\bfrakE" "𝕰" julia-latexsubs) +(puthash "\\bfrakF" "𝕱" julia-latexsubs) +(puthash "\\bfrakG" "𝕲" julia-latexsubs) +(puthash "\\bfrakH" "𝕳" julia-latexsubs) +(puthash "\\bfrakI" "𝕴" julia-latexsubs) +(puthash "\\bfrakJ" "𝕵" julia-latexsubs) +(puthash "\\bfrakK" "𝕶" julia-latexsubs) +(puthash "\\bfrakL" "𝕷" julia-latexsubs) +(puthash "\\bfrakM" "𝕸" julia-latexsubs) +(puthash "\\bfrakN" "𝕹" julia-latexsubs) +(puthash "\\bfrakO" "𝕺" julia-latexsubs) +(puthash "\\bfrakP" "𝕻" julia-latexsubs) +(puthash "\\bfrakQ" "𝕼" julia-latexsubs) +(puthash "\\bfrakR" "𝕽" julia-latexsubs) +(puthash "\\bfrakS" "𝕾" julia-latexsubs) +(puthash "\\bfrakT" "𝕿" julia-latexsubs) +(puthash "\\bfrakU" "𝖀" julia-latexsubs) +(puthash "\\bfrakV" "𝖁" julia-latexsubs) +(puthash "\\bfrakW" "𝖂" julia-latexsubs) +(puthash "\\bfrakX" "𝖃" julia-latexsubs) +(puthash "\\bfrakY" "𝖄" julia-latexsubs) +(puthash "\\bfrakZ" "𝖅" julia-latexsubs) +(puthash "\\bfraka" "𝖆" julia-latexsubs) +(puthash "\\bfrakb" "𝖇" julia-latexsubs) +(puthash "\\bfrakc" "𝖈" julia-latexsubs) +(puthash "\\bfrakd" "𝖉" julia-latexsubs) +(puthash "\\bfrake" "𝖊" julia-latexsubs) +(puthash "\\bfrakf" "𝖋" julia-latexsubs) +(puthash "\\bfrakg" "𝖌" julia-latexsubs) +(puthash "\\bfrakh" "𝖍" julia-latexsubs) +(puthash "\\bfraki" "𝖎" julia-latexsubs) +(puthash "\\bfrakj" "𝖏" julia-latexsubs) +(puthash "\\bfrakk" "𝖐" julia-latexsubs) +(puthash "\\bfrakl" "𝖑" julia-latexsubs) +(puthash "\\bfrakm" "𝖒" julia-latexsubs) +(puthash "\\bfrakn" "𝖓" julia-latexsubs) +(puthash "\\bfrako" "𝖔" julia-latexsubs) +(puthash "\\bfrakp" "𝖕" julia-latexsubs) +(puthash "\\bfrakq" "𝖖" julia-latexsubs) +(puthash "\\bfrakr" "𝖗" julia-latexsubs) +(puthash "\\bfraks" "𝖘" julia-latexsubs) +(puthash "\\bfrakt" "𝖙" julia-latexsubs) +(puthash "\\bfraku" "𝖚" julia-latexsubs) +(puthash "\\bfrakv" "𝖛" julia-latexsubs) +(puthash "\\bfrakw" "𝖜" julia-latexsubs) +(puthash "\\bfrakx" "𝖝" julia-latexsubs) +(puthash "\\bfraky" "𝖞" julia-latexsubs) +(puthash "\\bfrakz" "𝖟" julia-latexsubs) +(puthash "\\sansA" "𝖠" julia-latexsubs) +(puthash "\\sansB" "𝖡" julia-latexsubs) +(puthash "\\sansC" "𝖢" julia-latexsubs) +(puthash "\\sansD" "𝖣" julia-latexsubs) +(puthash "\\sansE" "𝖤" julia-latexsubs) +(puthash "\\sansF" "𝖥" julia-latexsubs) +(puthash "\\sansG" "𝖦" julia-latexsubs) +(puthash "\\sansH" "𝖧" julia-latexsubs) +(puthash "\\sansI" "𝖨" julia-latexsubs) +(puthash "\\sansJ" "𝖩" julia-latexsubs) +(puthash "\\sansK" "𝖪" julia-latexsubs) +(puthash "\\sansL" "𝖫" julia-latexsubs) +(puthash "\\sansM" "𝖬" julia-latexsubs) +(puthash "\\sansN" "𝖭" julia-latexsubs) +(puthash "\\sansO" "𝖮" julia-latexsubs) +(puthash "\\sansP" "𝖯" julia-latexsubs) +(puthash "\\sansQ" "𝖰" julia-latexsubs) +(puthash "\\sansR" "𝖱" julia-latexsubs) +(puthash "\\sansS" "𝖲" julia-latexsubs) +(puthash "\\sansT" "𝖳" julia-latexsubs) +(puthash "\\sansU" "𝖴" julia-latexsubs) +(puthash "\\sansV" "𝖵" julia-latexsubs) +(puthash "\\sansW" "𝖶" julia-latexsubs) +(puthash "\\sansX" "𝖷" julia-latexsubs) +(puthash "\\sansY" "𝖸" julia-latexsubs) +(puthash "\\sansZ" "𝖹" julia-latexsubs) +(puthash "\\sansa" "𝖺" julia-latexsubs) +(puthash "\\sansb" "𝖻" julia-latexsubs) +(puthash "\\sansc" "𝖼" julia-latexsubs) +(puthash "\\sansd" "𝖽" julia-latexsubs) +(puthash "\\sanse" "𝖾" julia-latexsubs) +(puthash "\\sansf" "𝖿" julia-latexsubs) +(puthash "\\sansg" "𝗀" julia-latexsubs) +(puthash "\\sansh" "𝗁" julia-latexsubs) +(puthash "\\sansi" "𝗂" julia-latexsubs) +(puthash "\\sansj" "𝗃" julia-latexsubs) +(puthash "\\sansk" "𝗄" julia-latexsubs) +(puthash "\\sansl" "𝗅" julia-latexsubs) +(puthash "\\sansm" "𝗆" julia-latexsubs) +(puthash "\\sansn" "𝗇" julia-latexsubs) +(puthash "\\sanso" "𝗈" julia-latexsubs) +(puthash "\\sansp" "𝗉" julia-latexsubs) +(puthash "\\sansq" "𝗊" julia-latexsubs) +(puthash "\\sansr" "𝗋" julia-latexsubs) +(puthash "\\sanss" "𝗌" julia-latexsubs) +(puthash "\\sanst" "𝗍" julia-latexsubs) +(puthash "\\sansu" "𝗎" julia-latexsubs) +(puthash "\\sansv" "𝗏" julia-latexsubs) +(puthash "\\sansw" "𝗐" julia-latexsubs) +(puthash "\\sansx" "𝗑" julia-latexsubs) +(puthash "\\sansy" "𝗒" julia-latexsubs) +(puthash "\\sansz" "𝗓" julia-latexsubs) +(puthash "\\bsansA" "𝗔" julia-latexsubs) +(puthash "\\bsansB" "𝗕" julia-latexsubs) +(puthash "\\bsansC" "𝗖" julia-latexsubs) +(puthash "\\bsansD" "𝗗" julia-latexsubs) +(puthash "\\bsansE" "𝗘" julia-latexsubs) +(puthash "\\bsansF" "𝗙" julia-latexsubs) +(puthash "\\bsansG" "𝗚" julia-latexsubs) +(puthash "\\bsansH" "𝗛" julia-latexsubs) +(puthash "\\bsansI" "𝗜" julia-latexsubs) +(puthash "\\bsansJ" "𝗝" julia-latexsubs) +(puthash "\\bsansK" "𝗞" julia-latexsubs) +(puthash "\\bsansL" "𝗟" julia-latexsubs) +(puthash "\\bsansM" "𝗠" julia-latexsubs) +(puthash "\\bsansN" "𝗡" julia-latexsubs) +(puthash "\\bsansO" "𝗢" julia-latexsubs) +(puthash "\\bsansP" "𝗣" julia-latexsubs) +(puthash "\\bsansQ" "𝗤" julia-latexsubs) +(puthash "\\bsansR" "𝗥" julia-latexsubs) +(puthash "\\bsansS" "𝗦" julia-latexsubs) +(puthash "\\bsansT" "𝗧" julia-latexsubs) +(puthash "\\bsansU" "𝗨" julia-latexsubs) +(puthash "\\bsansV" "𝗩" julia-latexsubs) +(puthash "\\bsansW" "𝗪" julia-latexsubs) +(puthash "\\bsansX" "𝗫" julia-latexsubs) +(puthash "\\bsansY" "𝗬" julia-latexsubs) +(puthash "\\bsansZ" "𝗭" julia-latexsubs) +(puthash "\\bsansa" "𝗮" julia-latexsubs) +(puthash "\\bsansb" "𝗯" julia-latexsubs) +(puthash "\\bsansc" "𝗰" julia-latexsubs) +(puthash "\\bsansd" "𝗱" julia-latexsubs) +(puthash "\\bsanse" "𝗲" julia-latexsubs) +(puthash "\\bsansf" "𝗳" julia-latexsubs) +(puthash "\\bsansg" "𝗴" julia-latexsubs) +(puthash "\\bsansh" "𝗵" julia-latexsubs) +(puthash "\\bsansi" "𝗶" julia-latexsubs) +(puthash "\\bsansj" "𝗷" julia-latexsubs) +(puthash "\\bsansk" "𝗸" julia-latexsubs) +(puthash "\\bsansl" "𝗹" julia-latexsubs) +(puthash "\\bsansm" "𝗺" julia-latexsubs) +(puthash "\\bsansn" "𝗻" julia-latexsubs) +(puthash "\\bsanso" "𝗼" julia-latexsubs) +(puthash "\\bsansp" "𝗽" julia-latexsubs) +(puthash "\\bsansq" "𝗾" julia-latexsubs) +(puthash "\\bsansr" "𝗿" julia-latexsubs) +(puthash "\\bsanss" "𝘀" julia-latexsubs) +(puthash "\\bsanst" "𝘁" julia-latexsubs) +(puthash "\\bsansu" "𝘂" julia-latexsubs) +(puthash "\\bsansv" "𝘃" julia-latexsubs) +(puthash "\\bsansw" "𝘄" julia-latexsubs) +(puthash "\\bsansx" "𝘅" julia-latexsubs) +(puthash "\\bsansy" "𝘆" julia-latexsubs) +(puthash "\\bsansz" "𝘇" julia-latexsubs) +(puthash "\\isansA" "𝘈" julia-latexsubs) +(puthash "\\isansB" "𝘉" julia-latexsubs) +(puthash "\\isansC" "𝘊" julia-latexsubs) +(puthash "\\isansD" "𝘋" julia-latexsubs) +(puthash "\\isansE" "𝘌" julia-latexsubs) +(puthash "\\isansF" "𝘍" julia-latexsubs) +(puthash "\\isansG" "𝘎" julia-latexsubs) +(puthash "\\isansH" "𝘏" julia-latexsubs) +(puthash "\\isansI" "𝘐" julia-latexsubs) +(puthash "\\isansJ" "𝘑" julia-latexsubs) +(puthash "\\isansK" "𝘒" julia-latexsubs) +(puthash "\\isansL" "𝘓" julia-latexsubs) +(puthash "\\isansM" "𝘔" julia-latexsubs) +(puthash "\\isansN" "𝘕" julia-latexsubs) +(puthash "\\isansO" "𝘖" julia-latexsubs) +(puthash "\\isansP" "𝘗" julia-latexsubs) +(puthash "\\isansQ" "𝘘" julia-latexsubs) +(puthash "\\isansR" "𝘙" julia-latexsubs) +(puthash "\\isansS" "𝘚" julia-latexsubs) +(puthash "\\isansT" "𝘛" julia-latexsubs) +(puthash "\\isansU" "𝘜" julia-latexsubs) +(puthash "\\isansV" "𝘝" julia-latexsubs) +(puthash "\\isansW" "𝘞" julia-latexsubs) +(puthash "\\isansX" "𝘟" julia-latexsubs) +(puthash "\\isansY" "𝘠" julia-latexsubs) +(puthash "\\isansZ" "𝘡" julia-latexsubs) +(puthash "\\isansa" "𝘢" julia-latexsubs) +(puthash "\\isansb" "𝘣" julia-latexsubs) +(puthash "\\isansc" "𝘤" julia-latexsubs) +(puthash "\\isansd" "𝘥" julia-latexsubs) +(puthash "\\isanse" "𝘦" julia-latexsubs) +(puthash "\\isansf" "𝘧" julia-latexsubs) +(puthash "\\isansg" "𝘨" julia-latexsubs) +(puthash "\\isansh" "𝘩" julia-latexsubs) +(puthash "\\isansi" "𝘪" julia-latexsubs) +(puthash "\\isansj" "𝘫" julia-latexsubs) +(puthash "\\isansk" "𝘬" julia-latexsubs) +(puthash "\\isansl" "𝘭" julia-latexsubs) +(puthash "\\isansm" "𝘮" julia-latexsubs) +(puthash "\\isansn" "𝘯" julia-latexsubs) +(puthash "\\isanso" "𝘰" julia-latexsubs) +(puthash "\\isansp" "𝘱" julia-latexsubs) +(puthash "\\isansq" "𝘲" julia-latexsubs) +(puthash "\\isansr" "𝘳" julia-latexsubs) +(puthash "\\isanss" "𝘴" julia-latexsubs) +(puthash "\\isanst" "𝘵" julia-latexsubs) +(puthash "\\isansu" "𝘶" julia-latexsubs) +(puthash "\\isansv" "𝘷" julia-latexsubs) +(puthash "\\isansw" "𝘸" julia-latexsubs) +(puthash "\\isansx" "𝘹" julia-latexsubs) +(puthash "\\isansy" "𝘺" julia-latexsubs) +(puthash "\\isansz" "𝘻" julia-latexsubs) +(puthash "\\bisansA" "𝘼" julia-latexsubs) +(puthash "\\bisansB" "𝘽" julia-latexsubs) +(puthash "\\bisansC" "𝘾" julia-latexsubs) +(puthash "\\bisansD" "𝘿" julia-latexsubs) +(puthash "\\bisansE" "𝙀" julia-latexsubs) +(puthash "\\bisansF" "𝙁" julia-latexsubs) +(puthash "\\bisansG" "𝙂" julia-latexsubs) +(puthash "\\bisansH" "𝙃" julia-latexsubs) +(puthash "\\bisansI" "𝙄" julia-latexsubs) +(puthash "\\bisansJ" "𝙅" julia-latexsubs) +(puthash "\\bisansK" "𝙆" julia-latexsubs) +(puthash "\\bisansL" "𝙇" julia-latexsubs) +(puthash "\\bisansM" "𝙈" julia-latexsubs) +(puthash "\\bisansN" "𝙉" julia-latexsubs) +(puthash "\\bisansO" "𝙊" julia-latexsubs) +(puthash "\\bisansP" "𝙋" julia-latexsubs) +(puthash "\\bisansQ" "𝙌" julia-latexsubs) +(puthash "\\bisansR" "𝙍" julia-latexsubs) +(puthash "\\bisansS" "𝙎" julia-latexsubs) +(puthash "\\bisansT" "𝙏" julia-latexsubs) +(puthash "\\bisansU" "𝙐" julia-latexsubs) +(puthash "\\bisansV" "𝙑" julia-latexsubs) +(puthash "\\bisansW" "𝙒" julia-latexsubs) +(puthash "\\bisansX" "𝙓" julia-latexsubs) +(puthash "\\bisansY" "𝙔" julia-latexsubs) +(puthash "\\bisansZ" "𝙕" julia-latexsubs) +(puthash "\\bisansa" "𝙖" julia-latexsubs) +(puthash "\\bisansb" "𝙗" julia-latexsubs) +(puthash "\\bisansc" "𝙘" julia-latexsubs) +(puthash "\\bisansd" "𝙙" julia-latexsubs) +(puthash "\\bisanse" "𝙚" julia-latexsubs) +(puthash "\\bisansf" "𝙛" julia-latexsubs) +(puthash "\\bisansg" "𝙜" julia-latexsubs) +(puthash "\\bisansh" "𝙝" julia-latexsubs) +(puthash "\\bisansi" "𝙞" julia-latexsubs) +(puthash "\\bisansj" "𝙟" julia-latexsubs) +(puthash "\\bisansk" "𝙠" julia-latexsubs) +(puthash "\\bisansl" "𝙡" julia-latexsubs) +(puthash "\\bisansm" "𝙢" julia-latexsubs) +(puthash "\\bisansn" "𝙣" julia-latexsubs) +(puthash "\\bisanso" "𝙤" julia-latexsubs) +(puthash "\\bisansp" "𝙥" julia-latexsubs) +(puthash "\\bisansq" "𝙦" julia-latexsubs) +(puthash "\\bisansr" "𝙧" julia-latexsubs) +(puthash "\\bisanss" "𝙨" julia-latexsubs) +(puthash "\\bisanst" "𝙩" julia-latexsubs) +(puthash "\\bisansu" "𝙪" julia-latexsubs) +(puthash "\\bisansv" "𝙫" julia-latexsubs) +(puthash "\\bisansw" "𝙬" julia-latexsubs) +(puthash "\\bisansx" "𝙭" julia-latexsubs) +(puthash "\\bisansy" "𝙮" julia-latexsubs) +(puthash "\\bisansz" "𝙯" julia-latexsubs) +(puthash "\\ttA" "𝙰" julia-latexsubs) +(puthash "\\ttB" "𝙱" julia-latexsubs) +(puthash "\\ttC" "𝙲" julia-latexsubs) +(puthash "\\ttD" "𝙳" julia-latexsubs) +(puthash "\\ttE" "𝙴" julia-latexsubs) +(puthash "\\ttF" "𝙵" julia-latexsubs) +(puthash "\\ttG" "𝙶" julia-latexsubs) +(puthash "\\ttH" "𝙷" julia-latexsubs) +(puthash "\\ttI" "𝙸" julia-latexsubs) +(puthash "\\ttJ" "𝙹" julia-latexsubs) +(puthash "\\ttK" "𝙺" julia-latexsubs) +(puthash "\\ttL" "𝙻" julia-latexsubs) +(puthash "\\ttM" "𝙼" julia-latexsubs) +(puthash "\\ttN" "𝙽" julia-latexsubs) +(puthash "\\ttO" "𝙾" julia-latexsubs) +(puthash "\\ttP" "𝙿" julia-latexsubs) +(puthash "\\ttQ" "𝚀" julia-latexsubs) +(puthash "\\ttR" "𝚁" julia-latexsubs) +(puthash "\\ttS" "𝚂" julia-latexsubs) +(puthash "\\ttT" "𝚃" julia-latexsubs) +(puthash "\\ttU" "𝚄" julia-latexsubs) +(puthash "\\ttV" "𝚅" julia-latexsubs) +(puthash "\\ttW" "𝚆" julia-latexsubs) +(puthash "\\ttX" "𝚇" julia-latexsubs) +(puthash "\\ttY" "𝚈" julia-latexsubs) +(puthash "\\ttZ" "𝚉" julia-latexsubs) +(puthash "\\tta" "𝚊" julia-latexsubs) +(puthash "\\ttb" "𝚋" julia-latexsubs) +(puthash "\\ttc" "𝚌" julia-latexsubs) +(puthash "\\ttd" "𝚍" julia-latexsubs) +(puthash "\\tte" "𝚎" julia-latexsubs) +(puthash "\\ttf" "𝚏" julia-latexsubs) +(puthash "\\ttg" "𝚐" julia-latexsubs) +(puthash "\\tth" "𝚑" julia-latexsubs) +(puthash "\\tti" "𝚒" julia-latexsubs) +(puthash "\\ttj" "𝚓" julia-latexsubs) +(puthash "\\ttk" "𝚔" julia-latexsubs) +(puthash "\\ttl" "𝚕" julia-latexsubs) +(puthash "\\ttm" "𝚖" julia-latexsubs) +(puthash "\\ttn" "𝚗" julia-latexsubs) +(puthash "\\tto" "𝚘" julia-latexsubs) +(puthash "\\ttp" "𝚙" julia-latexsubs) +(puthash "\\ttq" "𝚚" julia-latexsubs) +(puthash "\\ttr" "𝚛" julia-latexsubs) +(puthash "\\tts" "𝚜" julia-latexsubs) +(puthash "\\ttt" "𝚝" julia-latexsubs) +(puthash "\\ttu" "𝚞" julia-latexsubs) +(puthash "\\ttv" "𝚟" julia-latexsubs) +(puthash "\\ttw" "𝚠" julia-latexsubs) +(puthash "\\ttx" "𝚡" julia-latexsubs) +(puthash "\\tty" "𝚢" julia-latexsubs) +(puthash "\\ttz" "𝚣" julia-latexsubs) +(puthash "\\itimath" "𝚤" julia-latexsubs) +(puthash "\\itjmath" "𝚥" julia-latexsubs) +(puthash "\\bfAlpha" "𝚨" julia-latexsubs) +(puthash "\\bfBeta" "𝚩" julia-latexsubs) +(puthash "\\bfGamma" "𝚪" julia-latexsubs) +(puthash "\\bfDelta" "𝚫" julia-latexsubs) +(puthash "\\bfEpsilon" "𝚬" julia-latexsubs) +(puthash "\\bfZeta" "𝚭" julia-latexsubs) +(puthash "\\bfEta" "𝚮" julia-latexsubs) +(puthash "\\bfTheta" "𝚯" julia-latexsubs) +(puthash "\\bfIota" "𝚰" julia-latexsubs) +(puthash "\\bfKappa" "𝚱" julia-latexsubs) +(puthash "\\bfLambda" "𝚲" julia-latexsubs) +(puthash "\\bfMu" "𝚳" julia-latexsubs) +(puthash "\\bfNu" "𝚴" julia-latexsubs) +(puthash "\\bfXi" "𝚵" julia-latexsubs) +(puthash "\\bfOmicron" "𝚶" julia-latexsubs) +(puthash "\\bfPi" "𝚷" julia-latexsubs) +(puthash "\\bfRho" "𝚸" julia-latexsubs) +(puthash "\\bfvarTheta" "𝚹" julia-latexsubs) +(puthash "\\bfSigma" "𝚺" julia-latexsubs) +(puthash "\\bfTau" "𝚻" julia-latexsubs) +(puthash "\\bfUpsilon" "𝚼" julia-latexsubs) +(puthash "\\bfPhi" "𝚽" julia-latexsubs) +(puthash "\\bfChi" "𝚾" julia-latexsubs) +(puthash "\\bfPsi" "𝚿" julia-latexsubs) +(puthash "\\bfOmega" "𝛀" julia-latexsubs) +(puthash "\\bfnabla" "𝛁" julia-latexsubs) +(puthash "\\bfalpha" "𝛂" julia-latexsubs) +(puthash "\\bfbeta" "𝛃" julia-latexsubs) +(puthash "\\bfgamma" "𝛄" julia-latexsubs) +(puthash "\\bfdelta" "𝛅" julia-latexsubs) +(puthash "\\bfepsilon" "𝛆" julia-latexsubs) +(puthash "\\bfzeta" "𝛇" julia-latexsubs) +(puthash "\\bfeta" "𝛈" julia-latexsubs) +(puthash "\\bftheta" "𝛉" julia-latexsubs) +(puthash "\\bfiota" "𝛊" julia-latexsubs) +(puthash "\\bfkappa" "𝛋" julia-latexsubs) +(puthash "\\bflambda" "𝛌" julia-latexsubs) +(puthash "\\bfmu" "𝛍" julia-latexsubs) +(puthash "\\bfnu" "𝛎" julia-latexsubs) +(puthash "\\bfxi" "𝛏" julia-latexsubs) +(puthash "\\bfomicron" "𝛐" julia-latexsubs) +(puthash "\\bfpi" "𝛑" julia-latexsubs) +(puthash "\\bfrho" "𝛒" julia-latexsubs) +(puthash "\\bfvarsigma" "𝛓" julia-latexsubs) +(puthash "\\bfsigma" "𝛔" julia-latexsubs) +(puthash "\\bftau" "𝛕" julia-latexsubs) +(puthash "\\bfupsilon" "𝛖" julia-latexsubs) +(puthash "\\bfvarphi" "𝛗" julia-latexsubs) +(puthash "\\bfchi" "𝛘" julia-latexsubs) +(puthash "\\bfpsi" "𝛙" julia-latexsubs) +(puthash "\\bfomega" "𝛚" julia-latexsubs) +(puthash "\\bfpartial" "𝛛" julia-latexsubs) +(puthash "\\bfvarepsilon" "𝛜" julia-latexsubs) +(puthash "\\bfvartheta" "𝛝" julia-latexsubs) +(puthash "\\bfvarkappa" "𝛞" julia-latexsubs) +(puthash "\\bfphi" "𝛟" julia-latexsubs) +(puthash "\\bfvarrho" "𝛠" julia-latexsubs) +(puthash "\\bfvarpi" "𝛡" julia-latexsubs) +(puthash "\\itAlpha" "𝛢" julia-latexsubs) +(puthash "\\itBeta" "𝛣" julia-latexsubs) +(puthash "\\itGamma" "𝛤" julia-latexsubs) +(puthash "\\itDelta" "𝛥" julia-latexsubs) +(puthash "\\itEpsilon" "𝛦" julia-latexsubs) +(puthash "\\itZeta" "𝛧" julia-latexsubs) +(puthash "\\itEta" "𝛨" julia-latexsubs) +(puthash "\\itTheta" "𝛩" julia-latexsubs) +(puthash "\\itIota" "𝛪" julia-latexsubs) +(puthash "\\itKappa" "𝛫" julia-latexsubs) +(puthash "\\itLambda" "𝛬" julia-latexsubs) +(puthash "\\itMu" "𝛭" julia-latexsubs) +(puthash "\\itNu" "𝛮" julia-latexsubs) +(puthash "\\itXi" "𝛯" julia-latexsubs) +(puthash "\\itOmicron" "𝛰" julia-latexsubs) +(puthash "\\itPi" "𝛱" julia-latexsubs) +(puthash "\\itRho" "𝛲" julia-latexsubs) +(puthash "\\itvarTheta" "𝛳" julia-latexsubs) +(puthash "\\itSigma" "𝛴" julia-latexsubs) +(puthash "\\itTau" "𝛵" julia-latexsubs) +(puthash "\\itUpsilon" "𝛶" julia-latexsubs) +(puthash "\\itPhi" "𝛷" julia-latexsubs) +(puthash "\\itChi" "𝛸" julia-latexsubs) +(puthash "\\itPsi" "𝛹" julia-latexsubs) +(puthash "\\itOmega" "𝛺" julia-latexsubs) +(puthash "\\itnabla" "𝛻" julia-latexsubs) +(puthash "\\italpha" "𝛼" julia-latexsubs) +(puthash "\\itbeta" "𝛽" julia-latexsubs) +(puthash "\\itgamma" "𝛾" julia-latexsubs) +(puthash "\\itdelta" "𝛿" julia-latexsubs) +(puthash "\\itepsilon" "𝜀" julia-latexsubs) +(puthash "\\itzeta" "𝜁" julia-latexsubs) +(puthash "\\iteta" "𝜂" julia-latexsubs) +(puthash "\\ittheta" "𝜃" julia-latexsubs) +(puthash "\\itiota" "𝜄" julia-latexsubs) +(puthash "\\itkappa" "𝜅" julia-latexsubs) +(puthash "\\itlambda" "𝜆" julia-latexsubs) +(puthash "\\itmu" "𝜇" julia-latexsubs) +(puthash "\\itnu" "𝜈" julia-latexsubs) +(puthash "\\itxi" "𝜉" julia-latexsubs) +(puthash "\\itomicron" "𝜊" julia-latexsubs) +(puthash "\\itpi" "𝜋" julia-latexsubs) +(puthash "\\itrho" "𝜌" julia-latexsubs) +(puthash "\\itvarsigma" "𝜍" julia-latexsubs) +(puthash "\\itsigma" "𝜎" julia-latexsubs) +(puthash "\\ittau" "𝜏" julia-latexsubs) +(puthash "\\itupsilon" "𝜐" julia-latexsubs) +(puthash "\\itphi" "𝜑" julia-latexsubs) +(puthash "\\itchi" "𝜒" julia-latexsubs) +(puthash "\\itpsi" "𝜓" julia-latexsubs) +(puthash "\\itomega" "𝜔" julia-latexsubs) +(puthash "\\itpartial" "𝜕" julia-latexsubs) +(puthash "\\itvarepsilon" "𝜖" julia-latexsubs) +(puthash "\\itvartheta" "𝜗" julia-latexsubs) +(puthash "\\itvarkappa" "𝜘" julia-latexsubs) +(puthash "\\itvarphi" "𝜙" julia-latexsubs) +(puthash "\\itvarrho" "𝜚" julia-latexsubs) +(puthash "\\itvarpi" "𝜛" julia-latexsubs) +(puthash "\\biAlpha" "𝜜" julia-latexsubs) +(puthash "\\biBeta" "𝜝" julia-latexsubs) +(puthash "\\biGamma" "𝜞" julia-latexsubs) +(puthash "\\biDelta" "𝜟" julia-latexsubs) +(puthash "\\biEpsilon" "𝜠" julia-latexsubs) +(puthash "\\biZeta" "𝜡" julia-latexsubs) +(puthash "\\biEta" "𝜢" julia-latexsubs) +(puthash "\\biTheta" "𝜣" julia-latexsubs) +(puthash "\\biIota" "𝜤" julia-latexsubs) +(puthash "\\biKappa" "𝜥" julia-latexsubs) +(puthash "\\biLambda" "𝜦" julia-latexsubs) +(puthash "\\biMu" "𝜧" julia-latexsubs) +(puthash "\\biNu" "𝜨" julia-latexsubs) +(puthash "\\biXi" "𝜩" julia-latexsubs) +(puthash "\\biOmicron" "𝜪" julia-latexsubs) +(puthash "\\biPi" "𝜫" julia-latexsubs) +(puthash "\\biRho" "𝜬" julia-latexsubs) +(puthash "\\bivarTheta" "𝜭" julia-latexsubs) +(puthash "\\biSigma" "𝜮" julia-latexsubs) +(puthash "\\biTau" "𝜯" julia-latexsubs) +(puthash "\\biUpsilon" "𝜰" julia-latexsubs) +(puthash "\\biPhi" "𝜱" julia-latexsubs) +(puthash "\\biChi" "𝜲" julia-latexsubs) +(puthash "\\biPsi" "𝜳" julia-latexsubs) +(puthash "\\biOmega" "𝜴" julia-latexsubs) +(puthash "\\binabla" "𝜵" julia-latexsubs) +(puthash "\\bialpha" "𝜶" julia-latexsubs) +(puthash "\\bibeta" "𝜷" julia-latexsubs) +(puthash "\\bigamma" "𝜸" julia-latexsubs) +(puthash "\\bidelta" "𝜹" julia-latexsubs) +(puthash "\\biepsilon" "𝜺" julia-latexsubs) +(puthash "\\bizeta" "𝜻" julia-latexsubs) +(puthash "\\bieta" "𝜼" julia-latexsubs) +(puthash "\\bitheta" "𝜽" julia-latexsubs) +(puthash "\\biiota" "𝜾" julia-latexsubs) +(puthash "\\bikappa" "𝜿" julia-latexsubs) +(puthash "\\bilambda" "𝝀" julia-latexsubs) +(puthash "\\bimu" "𝝁" julia-latexsubs) +(puthash "\\binu" "𝝂" julia-latexsubs) +(puthash "\\bixi" "𝝃" julia-latexsubs) +(puthash "\\biomicron" "𝝄" julia-latexsubs) +(puthash "\\bipi" "𝝅" julia-latexsubs) +(puthash "\\birho" "𝝆" julia-latexsubs) +(puthash "\\bivarsigma" "𝝇" julia-latexsubs) +(puthash "\\bisigma" "𝝈" julia-latexsubs) +(puthash "\\bitau" "𝝉" julia-latexsubs) +(puthash "\\biupsilon" "𝝊" julia-latexsubs) +(puthash "\\biphi" "𝝋" julia-latexsubs) +(puthash "\\bichi" "𝝌" julia-latexsubs) +(puthash "\\bipsi" "𝝍" julia-latexsubs) +(puthash "\\biomega" "𝝎" julia-latexsubs) +(puthash "\\bipartial" "𝝏" julia-latexsubs) +(puthash "\\bivarepsilon" "𝝐" julia-latexsubs) +(puthash "\\bivartheta" "𝝑" julia-latexsubs) +(puthash "\\bivarkappa" "𝝒" julia-latexsubs) +(puthash "\\bivarphi" "𝝓" julia-latexsubs) +(puthash "\\bivarrho" "𝝔" julia-latexsubs) +(puthash "\\bivarpi" "𝝕" julia-latexsubs) +(puthash "\\bsansAlpha" "𝝖" julia-latexsubs) +(puthash "\\bsansBeta" "𝝗" julia-latexsubs) +(puthash "\\bsansGamma" "𝝘" julia-latexsubs) +(puthash "\\bsansDelta" "𝝙" julia-latexsubs) +(puthash "\\bsansEpsilon" "𝝚" julia-latexsubs) +(puthash "\\bsansZeta" "𝝛" julia-latexsubs) +(puthash "\\bsansEta" "𝝜" julia-latexsubs) +(puthash "\\bsansTheta" "𝝝" julia-latexsubs) +(puthash "\\bsansIota" "𝝞" julia-latexsubs) +(puthash "\\bsansKappa" "𝝟" julia-latexsubs) +(puthash "\\bsansLambda" "𝝠" julia-latexsubs) +(puthash "\\bsansMu" "𝝡" julia-latexsubs) +(puthash "\\bsansNu" "𝝢" julia-latexsubs) +(puthash "\\bsansXi" "𝝣" julia-latexsubs) +(puthash "\\bsansOmicron" "𝝤" julia-latexsubs) +(puthash "\\bsansPi" "𝝥" julia-latexsubs) +(puthash "\\bsansRho" "𝝦" julia-latexsubs) +(puthash "\\bsansvarTheta" "𝝧" julia-latexsubs) +(puthash "\\bsansSigma" "𝝨" julia-latexsubs) +(puthash "\\bsansTau" "𝝩" julia-latexsubs) +(puthash "\\bsansUpsilon" "𝝪" julia-latexsubs) +(puthash "\\bsansPhi" "𝝫" julia-latexsubs) +(puthash "\\bsansChi" "𝝬" julia-latexsubs) +(puthash "\\bsansPsi" "𝝭" julia-latexsubs) +(puthash "\\bsansOmega" "𝝮" julia-latexsubs) +(puthash "\\bsansnabla" "𝝯" julia-latexsubs) +(puthash "\\bsansalpha" "𝝰" julia-latexsubs) +(puthash "\\bsansbeta" "𝝱" julia-latexsubs) +(puthash "\\bsansgamma" "𝝲" julia-latexsubs) +(puthash "\\bsansdelta" "𝝳" julia-latexsubs) +(puthash "\\bsansepsilon" "𝝴" julia-latexsubs) +(puthash "\\bsanszeta" "𝝵" julia-latexsubs) +(puthash "\\bsanseta" "𝝶" julia-latexsubs) +(puthash "\\bsanstheta" "𝝷" julia-latexsubs) +(puthash "\\bsansiota" "𝝸" julia-latexsubs) +(puthash "\\bsanskappa" "𝝹" julia-latexsubs) +(puthash "\\bsanslambda" "𝝺" julia-latexsubs) +(puthash "\\bsansmu" "𝝻" julia-latexsubs) +(puthash "\\bsansnu" "𝝼" julia-latexsubs) +(puthash "\\bsansxi" "𝝽" julia-latexsubs) +(puthash "\\bsansomicron" "𝝾" julia-latexsubs) +(puthash "\\bsanspi" "𝝿" julia-latexsubs) +(puthash "\\bsansrho" "𝞀" julia-latexsubs) +(puthash "\\bsansvarsigma" "𝞁" julia-latexsubs) +(puthash "\\bsanssigma" "𝞂" julia-latexsubs) +(puthash "\\bsanstau" "𝞃" julia-latexsubs) +(puthash "\\bsansupsilon" "𝞄" julia-latexsubs) +(puthash "\\bsansphi" "𝞅" julia-latexsubs) +(puthash "\\bsanschi" "𝞆" julia-latexsubs) +(puthash "\\bsanspsi" "𝞇" julia-latexsubs) +(puthash "\\bsansomega" "𝞈" julia-latexsubs) +(puthash "\\bsanspartial" "𝞉" julia-latexsubs) +(puthash "\\bsansvarepsilon" "𝞊" julia-latexsubs) +(puthash "\\bsansvartheta" "𝞋" julia-latexsubs) +(puthash "\\bsansvarkappa" "𝞌" julia-latexsubs) +(puthash "\\bsansvarphi" "𝞍" julia-latexsubs) +(puthash "\\bsansvarrho" "𝞎" julia-latexsubs) +(puthash "\\bsansvarpi" "𝞏" julia-latexsubs) +(puthash "\\bisansAlpha" "𝞐" julia-latexsubs) +(puthash "\\bisansBeta" "𝞑" julia-latexsubs) +(puthash "\\bisansGamma" "𝞒" julia-latexsubs) +(puthash "\\bisansDelta" "𝞓" julia-latexsubs) +(puthash "\\bisansEpsilon" "𝞔" julia-latexsubs) +(puthash "\\bisansZeta" "𝞕" julia-latexsubs) +(puthash "\\bisansEta" "𝞖" julia-latexsubs) +(puthash "\\bisansTheta" "𝞗" julia-latexsubs) +(puthash "\\bisansIota" "𝞘" julia-latexsubs) +(puthash "\\bisansKappa" "𝞙" julia-latexsubs) +(puthash "\\bisansLambda" "𝞚" julia-latexsubs) +(puthash "\\bisansMu" "𝞛" julia-latexsubs) +(puthash "\\bisansNu" "𝞜" julia-latexsubs) +(puthash "\\bisansXi" "𝞝" julia-latexsubs) +(puthash "\\bisansOmicron" "𝞞" julia-latexsubs) +(puthash "\\bisansPi" "𝞟" julia-latexsubs) +(puthash "\\bisansRho" "𝞠" julia-latexsubs) +(puthash "\\bisansvarTheta" "𝞡" julia-latexsubs) +(puthash "\\bisansSigma" "𝞢" julia-latexsubs) +(puthash "\\bisansTau" "𝞣" julia-latexsubs) +(puthash "\\bisansUpsilon" "𝞤" julia-latexsubs) +(puthash "\\bisansPhi" "𝞥" julia-latexsubs) +(puthash "\\bisansChi" "𝞦" julia-latexsubs) +(puthash "\\bisansPsi" "𝞧" julia-latexsubs) +(puthash "\\bisansOmega" "𝞨" julia-latexsubs) +(puthash "\\bisansnabla" "𝞩" julia-latexsubs) +(puthash "\\bisansalpha" "𝞪" julia-latexsubs) +(puthash "\\bisansbeta" "𝞫" julia-latexsubs) +(puthash "\\bisansgamma" "𝞬" julia-latexsubs) +(puthash "\\bisansdelta" "𝞭" julia-latexsubs) +(puthash "\\bisansepsilon" "𝞮" julia-latexsubs) +(puthash "\\bisanszeta" "𝞯" julia-latexsubs) +(puthash "\\bisanseta" "𝞰" julia-latexsubs) +(puthash "\\bisanstheta" "𝞱" julia-latexsubs) +(puthash "\\bisansiota" "𝞲" julia-latexsubs) +(puthash "\\bisanskappa" "𝞳" julia-latexsubs) +(puthash "\\bisanslambda" "𝞴" julia-latexsubs) +(puthash "\\bisansmu" "𝞵" julia-latexsubs) +(puthash "\\bisansnu" "𝞶" julia-latexsubs) +(puthash "\\bisansxi" "𝞷" julia-latexsubs) +(puthash "\\bisansomicron" "𝞸" julia-latexsubs) +(puthash "\\bisanspi" "𝞹" julia-latexsubs) +(puthash "\\bisansrho" "𝞺" julia-latexsubs) +(puthash "\\bisansvarsigma" "𝞻" julia-latexsubs) +(puthash "\\bisanssigma" "𝞼" julia-latexsubs) +(puthash "\\bisanstau" "𝞽" julia-latexsubs) +(puthash "\\bisansupsilon" "𝞾" julia-latexsubs) +(puthash "\\bisansphi" "𝞿" julia-latexsubs) +(puthash "\\bisanschi" "𝟀" julia-latexsubs) +(puthash "\\bisanspsi" "𝟁" julia-latexsubs) +(puthash "\\bisansomega" "𝟂" julia-latexsubs) +(puthash "\\bisanspartial" "𝟃" julia-latexsubs) +(puthash "\\bisansvarepsilon" "𝟄" julia-latexsubs) +(puthash "\\bisansvartheta" "𝟅" julia-latexsubs) +(puthash "\\bisansvarkappa" "𝟆" julia-latexsubs) +(puthash "\\bisansvarphi" "𝟇" julia-latexsubs) +(puthash "\\bisansvarrho" "𝟈" julia-latexsubs) +(puthash "\\bisansvarpi" "𝟉" julia-latexsubs) +(puthash "\\bfDigamma" "𝟊" julia-latexsubs) +(puthash "\\bfdigamma" "𝟋" julia-latexsubs) +(puthash "\\bfzero" "𝟎" julia-latexsubs) +(puthash "\\bfone" "𝟏" julia-latexsubs) +(puthash "\\bftwo" "𝟐" julia-latexsubs) +(puthash "\\bfthree" "𝟑" julia-latexsubs) +(puthash "\\bffour" "𝟒" julia-latexsubs) +(puthash "\\bffive" "𝟓" julia-latexsubs) +(puthash "\\bfsix" "𝟔" julia-latexsubs) +(puthash "\\bfseven" "𝟕" julia-latexsubs) +(puthash "\\bfeight" "𝟖" julia-latexsubs) +(puthash "\\bfnine" "𝟗" julia-latexsubs) +(puthash "\\bbzero" "𝟘" julia-latexsubs) +(puthash "\\bbone" "𝟙" julia-latexsubs) +(puthash "\\bbtwo" "𝟚" julia-latexsubs) +(puthash "\\bbthree" "𝟛" julia-latexsubs) +(puthash "\\bbfour" "𝟜" julia-latexsubs) +(puthash "\\bbfive" "𝟝" julia-latexsubs) +(puthash "\\bbsix" "𝟞" julia-latexsubs) +(puthash "\\bbseven" "𝟟" julia-latexsubs) +(puthash "\\bbeight" "𝟠" julia-latexsubs) +(puthash "\\bbnine" "𝟡" julia-latexsubs) +(puthash "\\sanszero" "𝟢" julia-latexsubs) +(puthash "\\sansone" "𝟣" julia-latexsubs) +(puthash "\\sanstwo" "𝟤" julia-latexsubs) +(puthash "\\sansthree" "𝟥" julia-latexsubs) +(puthash "\\sansfour" "𝟦" julia-latexsubs) +(puthash "\\sansfive" "𝟧" julia-latexsubs) +(puthash "\\sanssix" "𝟨" julia-latexsubs) +(puthash "\\sansseven" "𝟩" julia-latexsubs) +(puthash "\\sanseight" "𝟪" julia-latexsubs) +(puthash "\\sansnine" "𝟫" julia-latexsubs) +(puthash "\\bsanszero" "𝟬" julia-latexsubs) +(puthash "\\bsansone" "𝟭" julia-latexsubs) +(puthash "\\bsanstwo" "𝟮" julia-latexsubs) +(puthash "\\bsansthree" "𝟯" julia-latexsubs) +(puthash "\\bsansfour" "𝟰" julia-latexsubs) +(puthash "\\bsansfive" "𝟱" julia-latexsubs) +(puthash "\\bsanssix" "𝟲" julia-latexsubs) +(puthash "\\bsansseven" "𝟳" julia-latexsubs) +(puthash "\\bsanseight" "𝟴" julia-latexsubs) +(puthash "\\bsansnine" "𝟵" julia-latexsubs) +(puthash "\\ttzero" "𝟶" julia-latexsubs) +(puthash "\\ttone" "𝟷" julia-latexsubs) +(puthash "\\tttwo" "𝟸" julia-latexsubs) +(puthash "\\ttthree" "𝟹" julia-latexsubs) +(puthash "\\ttfour" "𝟺" julia-latexsubs) +(puthash "\\ttfive" "𝟻" julia-latexsubs) +(puthash "\\ttsix" "𝟼" julia-latexsubs) +(puthash "\\ttseven" "𝟽" julia-latexsubs) +(puthash "\\tteight" "𝟾" julia-latexsubs) +(puthash "\\ttnine" "𝟿" julia-latexsubs) +(puthash "\\:mahjong:" "🀄" julia-latexsubs) +(puthash "\\:black_joker:" "🃏" julia-latexsubs) +(puthash "\\:a:" "🅰" julia-latexsubs) +(puthash "\\:b:" "🅱" julia-latexsubs) +(puthash "\\:o2:" "🅾" julia-latexsubs) +(puthash "\\:parking:" "🅿" julia-latexsubs) +(puthash "\\:ab:" "🆎" julia-latexsubs) +(puthash "\\:cl:" "🆑" julia-latexsubs) +(puthash "\\:cool:" "🆒" julia-latexsubs) +(puthash "\\:free:" "🆓" julia-latexsubs) +(puthash "\\:id:" "🆔" julia-latexsubs) +(puthash "\\:new:" "🆕" julia-latexsubs) +(puthash "\\:ng:" "🆖" julia-latexsubs) +(puthash "\\:ok:" "🆗" julia-latexsubs) +(puthash "\\:sos:" "🆘" julia-latexsubs) +(puthash "\\:up:" "🆙" julia-latexsubs) +(puthash "\\:vs:" "🆚" julia-latexsubs) +(puthash "\\:koko:" "🈁" julia-latexsubs) +(puthash "\\:sa:" "🈂" julia-latexsubs) +(puthash "\\:u7121:" "🈚" julia-latexsubs) +(puthash "\\:u6307:" "🈯" julia-latexsubs) +(puthash "\\:u7981:" "🈲" julia-latexsubs) +(puthash "\\:u7a7a:" "🈳" julia-latexsubs) +(puthash "\\:u5408:" "🈴" julia-latexsubs) +(puthash "\\:u6e80:" "🈵" julia-latexsubs) +(puthash "\\:u6709:" "🈶" julia-latexsubs) +(puthash "\\:u6708:" "🈷" julia-latexsubs) +(puthash "\\:u7533:" "🈸" julia-latexsubs) +(puthash "\\:u5272:" "🈹" julia-latexsubs) +(puthash "\\:u55b6:" "🈺" julia-latexsubs) +(puthash "\\:ideograph_advantage:" "🉐" julia-latexsubs) +(puthash "\\:accept:" "🉑" julia-latexsubs) +(puthash "\\:cyclone:" "🌀" julia-latexsubs) +(puthash "\\:foggy:" "🌁" julia-latexsubs) +(puthash "\\:closed_umbrella:" "🌂" julia-latexsubs) +(puthash "\\:night_with_stars:" "🌃" julia-latexsubs) +(puthash "\\:sunrise_over_mountains:" "🌄" julia-latexsubs) +(puthash "\\:sunrise:" "🌅" julia-latexsubs) +(puthash "\\:city_sunset:" "🌆" julia-latexsubs) +(puthash "\\:city_sunrise:" "🌇" julia-latexsubs) +(puthash "\\:rainbow:" "🌈" julia-latexsubs) +(puthash "\\:bridge_at_night:" "🌉" julia-latexsubs) +(puthash "\\:ocean:" "🌊" julia-latexsubs) +(puthash "\\:volcano:" "🌋" julia-latexsubs) +(puthash "\\:milky_way:" "🌌" julia-latexsubs) +(puthash "\\:earth_africa:" "🌍" julia-latexsubs) +(puthash "\\:earth_americas:" "🌎" julia-latexsubs) +(puthash "\\:earth_asia:" "🌏" julia-latexsubs) +(puthash "\\:globe_with_meridians:" "🌐" julia-latexsubs) +(puthash "\\:new_moon:" "🌑" julia-latexsubs) +(puthash "\\:waxing_crescent_moon:" "🌒" julia-latexsubs) +(puthash "\\:first_quarter_moon:" "🌓" julia-latexsubs) +(puthash "\\:moon:" "🌔" julia-latexsubs) +(puthash "\\:full_moon:" "🌕" julia-latexsubs) +(puthash "\\:waning_gibbous_moon:" "🌖" julia-latexsubs) +(puthash "\\:last_quarter_moon:" "🌗" julia-latexsubs) +(puthash "\\:waning_crescent_moon:" "🌘" julia-latexsubs) +(puthash "\\:crescent_moon:" "🌙" julia-latexsubs) +(puthash "\\:new_moon_with_face:" "🌚" julia-latexsubs) +(puthash "\\:first_quarter_moon_with_face:" "🌛" julia-latexsubs) +(puthash "\\:last_quarter_moon_with_face:" "🌜" julia-latexsubs) +(puthash "\\:full_moon_with_face:" "🌝" julia-latexsubs) +(puthash "\\:sun_with_face:" "🌞" julia-latexsubs) +(puthash "\\:star2:" "🌟" julia-latexsubs) +(puthash "\\:stars:" "🌠" julia-latexsubs) +(puthash "\\:chestnut:" "🌰" julia-latexsubs) +(puthash "\\:seedling:" "🌱" julia-latexsubs) +(puthash "\\:evergreen_tree:" "🌲" julia-latexsubs) +(puthash "\\:deciduous_tree:" "🌳" julia-latexsubs) +(puthash "\\:palm_tree:" "🌴" julia-latexsubs) +(puthash "\\:cactus:" "🌵" julia-latexsubs) +(puthash "\\:tulip:" "🌷" julia-latexsubs) +(puthash "\\:cherry_blossom:" "🌸" julia-latexsubs) +(puthash "\\:rose:" "🌹" julia-latexsubs) +(puthash "\\:hibiscus:" "🌺" julia-latexsubs) +(puthash "\\:sunflower:" "🌻" julia-latexsubs) +(puthash "\\:blossom:" "🌼" julia-latexsubs) +(puthash "\\:corn:" "🌽" julia-latexsubs) +(puthash "\\:ear_of_rice:" "🌾" julia-latexsubs) +(puthash "\\:herb:" "🌿" julia-latexsubs) +(puthash "\\:four_leaf_clover:" "🍀" julia-latexsubs) +(puthash "\\:maple_leaf:" "🍁" julia-latexsubs) +(puthash "\\:fallen_leaf:" "🍂" julia-latexsubs) +(puthash "\\:leaves:" "🍃" julia-latexsubs) +(puthash "\\:mushroom:" "🍄" julia-latexsubs) +(puthash "\\:tomato:" "🍅" julia-latexsubs) +(puthash "\\:eggplant:" "🍆" julia-latexsubs) +(puthash "\\:grapes:" "🍇" julia-latexsubs) +(puthash "\\:melon:" "🍈" julia-latexsubs) +(puthash "\\:watermelon:" "🍉" julia-latexsubs) +(puthash "\\:tangerine:" "🍊" julia-latexsubs) +(puthash "\\:lemon:" "🍋" julia-latexsubs) +(puthash "\\:banana:" "🍌" julia-latexsubs) +(puthash "\\:pineapple:" "🍍" julia-latexsubs) +(puthash "\\:apple:" "🍎" julia-latexsubs) +(puthash "\\:green_apple:" "🍏" julia-latexsubs) +(puthash "\\:pear:" "🍐" julia-latexsubs) +(puthash "\\:peach:" "🍑" julia-latexsubs) +(puthash "\\:cherries:" "🍒" julia-latexsubs) +(puthash "\\:strawberry:" "🍓" julia-latexsubs) +(puthash "\\:hamburger:" "🍔" julia-latexsubs) +(puthash "\\:pizza:" "🍕" julia-latexsubs) +(puthash "\\:meat_on_bone:" "🍖" julia-latexsubs) +(puthash "\\:poultry_leg:" "🍗" julia-latexsubs) +(puthash "\\:rice_cracker:" "🍘" julia-latexsubs) +(puthash "\\:rice_ball:" "🍙" julia-latexsubs) +(puthash "\\:rice:" "🍚" julia-latexsubs) +(puthash "\\:curry:" "🍛" julia-latexsubs) +(puthash "\\:ramen:" "🍜" julia-latexsubs) +(puthash "\\:spaghetti:" "🍝" julia-latexsubs) +(puthash "\\:bread:" "🍞" julia-latexsubs) +(puthash "\\:fries:" "🍟" julia-latexsubs) +(puthash "\\:sweet_potato:" "🍠" julia-latexsubs) +(puthash "\\:dango:" "🍡" julia-latexsubs) +(puthash "\\:oden:" "🍢" julia-latexsubs) +(puthash "\\:sushi:" "🍣" julia-latexsubs) +(puthash "\\:fried_shrimp:" "🍤" julia-latexsubs) +(puthash "\\:fish_cake:" "🍥" julia-latexsubs) +(puthash "\\:icecream:" "🍦" julia-latexsubs) +(puthash "\\:shaved_ice:" "🍧" julia-latexsubs) +(puthash "\\:ice_cream:" "🍨" julia-latexsubs) +(puthash "\\:doughnut:" "🍩" julia-latexsubs) +(puthash "\\:cookie:" "🍪" julia-latexsubs) +(puthash "\\:chocolate_bar:" "🍫" julia-latexsubs) +(puthash "\\:candy:" "🍬" julia-latexsubs) +(puthash "\\:lollipop:" "🍭" julia-latexsubs) +(puthash "\\:custard:" "🍮" julia-latexsubs) +(puthash "\\:honey_pot:" "🍯" julia-latexsubs) +(puthash "\\:cake:" "🍰" julia-latexsubs) +(puthash "\\:bento:" "🍱" julia-latexsubs) +(puthash "\\:stew:" "🍲" julia-latexsubs) +(puthash "\\:egg:" "🍳" julia-latexsubs) +(puthash "\\:fork_and_knife:" "🍴" julia-latexsubs) +(puthash "\\:tea:" "🍵" julia-latexsubs) +(puthash "\\:sake:" "🍶" julia-latexsubs) +(puthash "\\:wine_glass:" "🍷" julia-latexsubs) +(puthash "\\:cocktail:" "🍸" julia-latexsubs) +(puthash "\\:tropical_drink:" "🍹" julia-latexsubs) +(puthash "\\:beer:" "🍺" julia-latexsubs) +(puthash "\\:beers:" "🍻" julia-latexsubs) +(puthash "\\:baby_bottle:" "🍼" julia-latexsubs) +(puthash "\\:ribbon:" "🎀" julia-latexsubs) +(puthash "\\:gift:" "🎁" julia-latexsubs) +(puthash "\\:birthday:" "🎂" julia-latexsubs) +(puthash "\\:jack_o_lantern:" "🎃" julia-latexsubs) +(puthash "\\:christmas_tree:" "🎄" julia-latexsubs) +(puthash "\\:santa:" "🎅" julia-latexsubs) +(puthash "\\:fireworks:" "🎆" julia-latexsubs) +(puthash "\\:sparkler:" "🎇" julia-latexsubs) +(puthash "\\:balloon:" "🎈" julia-latexsubs) +(puthash "\\:tada:" "🎉" julia-latexsubs) +(puthash "\\:confetti_ball:" "🎊" julia-latexsubs) +(puthash "\\:tanabata_tree:" "🎋" julia-latexsubs) +(puthash "\\:crossed_flags:" "🎌" julia-latexsubs) +(puthash "\\:bamboo:" "🎍" julia-latexsubs) +(puthash "\\:dolls:" "🎎" julia-latexsubs) +(puthash "\\:flags:" "🎏" julia-latexsubs) +(puthash "\\:wind_chime:" "🎐" julia-latexsubs) +(puthash "\\:rice_scene:" "🎑" julia-latexsubs) +(puthash "\\:school_satchel:" "🎒" julia-latexsubs) +(puthash "\\:mortar_board:" "🎓" julia-latexsubs) +(puthash "\\:carousel_horse:" "🎠" julia-latexsubs) +(puthash "\\:ferris_wheel:" "🎡" julia-latexsubs) +(puthash "\\:roller_coaster:" "🎢" julia-latexsubs) +(puthash "\\:fishing_pole_and_fish:" "🎣" julia-latexsubs) +(puthash "\\:microphone:" "🎤" julia-latexsubs) +(puthash "\\:movie_camera:" "🎥" julia-latexsubs) +(puthash "\\:cinema:" "🎦" julia-latexsubs) +(puthash "\\:headphones:" "🎧" julia-latexsubs) +(puthash "\\:art:" "🎨" julia-latexsubs) +(puthash "\\:tophat:" "🎩" julia-latexsubs) +(puthash "\\:circus_tent:" "🎪" julia-latexsubs) +(puthash "\\:ticket:" "🎫" julia-latexsubs) +(puthash "\\:clapper:" "🎬" julia-latexsubs) +(puthash "\\:performing_arts:" "🎭" julia-latexsubs) +(puthash "\\:video_game:" "🎮" julia-latexsubs) +(puthash "\\:dart:" "🎯" julia-latexsubs) +(puthash "\\:slot_machine:" "🎰" julia-latexsubs) +(puthash "\\:8ball:" "🎱" julia-latexsubs) +(puthash "\\:game_die:" "🎲" julia-latexsubs) +(puthash "\\:bowling:" "🎳" julia-latexsubs) +(puthash "\\:flower_playing_cards:" "🎴" julia-latexsubs) +(puthash "\\:musical_note:" "🎵" julia-latexsubs) +(puthash "\\:notes:" "🎶" julia-latexsubs) +(puthash "\\:saxophone:" "🎷" julia-latexsubs) +(puthash "\\:guitar:" "🎸" julia-latexsubs) +(puthash "\\:musical_keyboard:" "🎹" julia-latexsubs) +(puthash "\\:trumpet:" "🎺" julia-latexsubs) +(puthash "\\:violin:" "🎻" julia-latexsubs) +(puthash "\\:musical_score:" "🎼" julia-latexsubs) +(puthash "\\:running_shirt_with_sash:" "🎽" julia-latexsubs) +(puthash "\\:tennis:" "🎾" julia-latexsubs) +(puthash "\\:ski:" "🎿" julia-latexsubs) +(puthash "\\:basketball:" "🏀" julia-latexsubs) +(puthash "\\:checkered_flag:" "🏁" julia-latexsubs) +(puthash "\\:snowboarder:" "🏂" julia-latexsubs) +(puthash "\\:runner:" "🏃" julia-latexsubs) +(puthash "\\:surfer:" "🏄" julia-latexsubs) +(puthash "\\:trophy:" "🏆" julia-latexsubs) +(puthash "\\:horse_racing:" "🏇" julia-latexsubs) +(puthash "\\:football:" "🏈" julia-latexsubs) +(puthash "\\:rugby_football:" "🏉" julia-latexsubs) +(puthash "\\:swimmer:" "🏊" julia-latexsubs) +(puthash "\\:house:" "🏠" julia-latexsubs) +(puthash "\\:house_with_garden:" "🏡" julia-latexsubs) +(puthash "\\:office:" "🏢" julia-latexsubs) +(puthash "\\:post_office:" "🏣" julia-latexsubs) +(puthash "\\:european_post_office:" "🏤" julia-latexsubs) +(puthash "\\:hospital:" "🏥" julia-latexsubs) +(puthash "\\:bank:" "🏦" julia-latexsubs) +(puthash "\\:atm:" "🏧" julia-latexsubs) +(puthash "\\:hotel:" "🏨" julia-latexsubs) +(puthash "\\:love_hotel:" "🏩" julia-latexsubs) +(puthash "\\:convenience_store:" "🏪" julia-latexsubs) +(puthash "\\:school:" "🏫" julia-latexsubs) +(puthash "\\:department_store:" "🏬" julia-latexsubs) +(puthash "\\:factory:" "🏭" julia-latexsubs) +(puthash "\\:izakaya_lantern:" "🏮" julia-latexsubs) +(puthash "\\:japanese_castle:" "🏯" julia-latexsubs) +(puthash "\\:european_castle:" "🏰" julia-latexsubs) +(puthash "\\:skin-tone-2:" "🏻" julia-latexsubs) +(puthash "\\:skin-tone-3:" "🏼" julia-latexsubs) +(puthash "\\:skin-tone-4:" "🏽" julia-latexsubs) +(puthash "\\:skin-tone-5:" "🏾" julia-latexsubs) +(puthash "\\:skin-tone-6:" "🏿" julia-latexsubs) +(puthash "\\:rat:" "🐀" julia-latexsubs) +(puthash "\\:mouse2:" "🐁" julia-latexsubs) +(puthash "\\:ox:" "🐂" julia-latexsubs) +(puthash "\\:water_buffalo:" "🐃" julia-latexsubs) +(puthash "\\:cow2:" "🐄" julia-latexsubs) +(puthash "\\:tiger2:" "🐅" julia-latexsubs) +(puthash "\\:leopard:" "🐆" julia-latexsubs) +(puthash "\\:rabbit2:" "🐇" julia-latexsubs) +(puthash "\\:cat2:" "🐈" julia-latexsubs) +(puthash "\\:dragon:" "🐉" julia-latexsubs) +(puthash "\\:crocodile:" "🐊" julia-latexsubs) +(puthash "\\:whale2:" "🐋" julia-latexsubs) +(puthash "\\:snail:" "🐌" julia-latexsubs) +(puthash "\\:snake:" "🐍" julia-latexsubs) +(puthash "\\:racehorse:" "🐎" julia-latexsubs) +(puthash "\\:ram:" "🐏" julia-latexsubs) +(puthash "\\:goat:" "🐐" julia-latexsubs) +(puthash "\\:sheep:" "🐑" julia-latexsubs) +(puthash "\\:monkey:" "🐒" julia-latexsubs) +(puthash "\\:rooster:" "🐓" julia-latexsubs) +(puthash "\\:chicken:" "🐔" julia-latexsubs) +(puthash "\\:dog2:" "🐕" julia-latexsubs) +(puthash "\\:pig2:" "🐖" julia-latexsubs) +(puthash "\\:boar:" "🐗" julia-latexsubs) +(puthash "\\:elephant:" "🐘" julia-latexsubs) +(puthash "\\:octopus:" "🐙" julia-latexsubs) +(puthash "\\:shell:" "🐚" julia-latexsubs) +(puthash "\\:bug:" "🐛" julia-latexsubs) +(puthash "\\:ant:" "🐜" julia-latexsubs) +(puthash "\\:bee:" "🐝" julia-latexsubs) +(puthash "\\:beetle:" "🐞" julia-latexsubs) +(puthash "\\:fish:" "🐟" julia-latexsubs) +(puthash "\\:tropical_fish:" "🐠" julia-latexsubs) +(puthash "\\:blowfish:" "🐡" julia-latexsubs) +(puthash "\\:turtle:" "🐢" julia-latexsubs) +(puthash "\\:hatching_chick:" "🐣" julia-latexsubs) +(puthash "\\:baby_chick:" "🐤" julia-latexsubs) +(puthash "\\:hatched_chick:" "🐥" julia-latexsubs) +(puthash "\\:bird:" "🐦" julia-latexsubs) +(puthash "\\:penguin:" "🐧" julia-latexsubs) +(puthash "\\:koala:" "🐨" julia-latexsubs) +(puthash "\\:poodle:" "🐩" julia-latexsubs) +(puthash "\\:dromedary_camel:" "🐪" julia-latexsubs) +(puthash "\\:camel:" "🐫" julia-latexsubs) +(puthash "\\:dolphin:" "🐬" julia-latexsubs) +(puthash "\\:mouse:" "🐭" julia-latexsubs) +(puthash "\\:cow:" "🐮" julia-latexsubs) +(puthash "\\:tiger:" "🐯" julia-latexsubs) +(puthash "\\:rabbit:" "🐰" julia-latexsubs) +(puthash "\\:cat:" "🐱" julia-latexsubs) +(puthash "\\:dragon_face:" "🐲" julia-latexsubs) +(puthash "\\:whale:" "🐳" julia-latexsubs) +(puthash "\\:horse:" "🐴" julia-latexsubs) +(puthash "\\:monkey_face:" "🐵" julia-latexsubs) +(puthash "\\:dog:" "🐶" julia-latexsubs) +(puthash "\\:pig:" "🐷" julia-latexsubs) +(puthash "\\:frog:" "🐸" julia-latexsubs) +(puthash "\\:hamster:" "🐹" julia-latexsubs) +(puthash "\\:wolf:" "🐺" julia-latexsubs) +(puthash "\\:bear:" "🐻" julia-latexsubs) +(puthash "\\:panda_face:" "🐼" julia-latexsubs) +(puthash "\\:pig_nose:" "🐽" julia-latexsubs) +(puthash "\\:feet:" "🐾" julia-latexsubs) +(puthash "\\:eyes:" "👀" julia-latexsubs) +(puthash "\\:ear:" "👂" julia-latexsubs) +(puthash "\\:nose:" "👃" julia-latexsubs) +(puthash "\\:lips:" "👄" julia-latexsubs) +(puthash "\\:tongue:" "👅" julia-latexsubs) +(puthash "\\:point_up_2:" "👆" julia-latexsubs) +(puthash "\\:point_down:" "👇" julia-latexsubs) +(puthash "\\:point_left:" "👈" julia-latexsubs) +(puthash "\\:point_right:" "👉" julia-latexsubs) +(puthash "\\:facepunch:" "👊" julia-latexsubs) +(puthash "\\:wave:" "👋" julia-latexsubs) +(puthash "\\:ok_hand:" "👌" julia-latexsubs) +(puthash "\\:+1:" "👍" julia-latexsubs) +(puthash "\\:-1:" "👎" julia-latexsubs) +(puthash "\\:clap:" "👏" julia-latexsubs) +(puthash "\\:open_hands:" "👐" julia-latexsubs) +(puthash "\\:crown:" "👑" julia-latexsubs) +(puthash "\\:womans_hat:" "👒" julia-latexsubs) +(puthash "\\:eyeglasses:" "👓" julia-latexsubs) +(puthash "\\:necktie:" "👔" julia-latexsubs) +(puthash "\\:shirt:" "👕" julia-latexsubs) +(puthash "\\:jeans:" "👖" julia-latexsubs) +(puthash "\\:dress:" "👗" julia-latexsubs) +(puthash "\\:kimono:" "👘" julia-latexsubs) +(puthash "\\:bikini:" "👙" julia-latexsubs) +(puthash "\\:womans_clothes:" "👚" julia-latexsubs) +(puthash "\\:purse:" "👛" julia-latexsubs) +(puthash "\\:handbag:" "👜" julia-latexsubs) +(puthash "\\:pouch:" "👝" julia-latexsubs) +(puthash "\\:mans_shoe:" "👞" julia-latexsubs) +(puthash "\\:athletic_shoe:" "👟" julia-latexsubs) +(puthash "\\:high_heel:" "👠" julia-latexsubs) +(puthash "\\:sandal:" "👡" julia-latexsubs) +(puthash "\\:boot:" "👢" julia-latexsubs) +(puthash "\\:footprints:" "👣" julia-latexsubs) +(puthash "\\:bust_in_silhouette:" "👤" julia-latexsubs) +(puthash "\\:busts_in_silhouette:" "👥" julia-latexsubs) +(puthash "\\:boy:" "👦" julia-latexsubs) +(puthash "\\:girl:" "👧" julia-latexsubs) +(puthash "\\:man:" "👨" julia-latexsubs) +(puthash "\\:woman:" "👩" julia-latexsubs) +(puthash "\\:family:" "👪" julia-latexsubs) +(puthash "\\:couple:" "👫" julia-latexsubs) +(puthash "\\:two_men_holding_hands:" "👬" julia-latexsubs) +(puthash "\\:two_women_holding_hands:" "👭" julia-latexsubs) +(puthash "\\:cop:" "👮" julia-latexsubs) +(puthash "\\:dancers:" "👯" julia-latexsubs) +(puthash "\\:bride_with_veil:" "👰" julia-latexsubs) +(puthash "\\:person_with_blond_hair:" "👱" julia-latexsubs) +(puthash "\\:man_with_gua_pi_mao:" "👲" julia-latexsubs) +(puthash "\\:man_with_turban:" "👳" julia-latexsubs) +(puthash "\\:older_man:" "👴" julia-latexsubs) +(puthash "\\:older_woman:" "👵" julia-latexsubs) +(puthash "\\:baby:" "👶" julia-latexsubs) +(puthash "\\:construction_worker:" "👷" julia-latexsubs) +(puthash "\\:princess:" "👸" julia-latexsubs) +(puthash "\\:japanese_ogre:" "👹" julia-latexsubs) +(puthash "\\:japanese_goblin:" "👺" julia-latexsubs) +(puthash "\\:ghost:" "👻" julia-latexsubs) +(puthash "\\:angel:" "👼" julia-latexsubs) +(puthash "\\:alien:" "👽" julia-latexsubs) +(puthash "\\:space_invader:" "👾" julia-latexsubs) +(puthash "\\:imp:" "👿" julia-latexsubs) +(puthash "\\:skull:" "💀" julia-latexsubs) +(puthash "\\:information_desk_person:" "💁" julia-latexsubs) +(puthash "\\:guardsman:" "💂" julia-latexsubs) +(puthash "\\:dancer:" "💃" julia-latexsubs) +(puthash "\\:lipstick:" "💄" julia-latexsubs) +(puthash "\\:nail_care:" "💅" julia-latexsubs) +(puthash "\\:massage:" "💆" julia-latexsubs) +(puthash "\\:haircut:" "💇" julia-latexsubs) +(puthash "\\:barber:" "💈" julia-latexsubs) +(puthash "\\:syringe:" "💉" julia-latexsubs) +(puthash "\\:pill:" "💊" julia-latexsubs) +(puthash "\\:kiss:" "💋" julia-latexsubs) +(puthash "\\:love_letter:" "💌" julia-latexsubs) +(puthash "\\:ring:" "💍" julia-latexsubs) +(puthash "\\:gem:" "💎" julia-latexsubs) +(puthash "\\:couplekiss:" "💏" julia-latexsubs) +(puthash "\\:bouquet:" "💐" julia-latexsubs) +(puthash "\\:couple_with_heart:" "💑" julia-latexsubs) +(puthash "\\:wedding:" "💒" julia-latexsubs) +(puthash "\\:heartbeat:" "💓" julia-latexsubs) +(puthash "\\:broken_heart:" "💔" julia-latexsubs) +(puthash "\\:two_hearts:" "💕" julia-latexsubs) +(puthash "\\:sparkling_heart:" "💖" julia-latexsubs) +(puthash "\\:heartpulse:" "💗" julia-latexsubs) +(puthash "\\:cupid:" "💘" julia-latexsubs) +(puthash "\\:blue_heart:" "💙" julia-latexsubs) +(puthash "\\:green_heart:" "💚" julia-latexsubs) +(puthash "\\:yellow_heart:" "💛" julia-latexsubs) +(puthash "\\:purple_heart:" "💜" julia-latexsubs) +(puthash "\\:gift_heart:" "💝" julia-latexsubs) +(puthash "\\:revolving_hearts:" "💞" julia-latexsubs) +(puthash "\\:heart_decoration:" "💟" julia-latexsubs) +(puthash "\\:diamond_shape_with_a_dot_inside:" "💠" julia-latexsubs) +(puthash "\\:bulb:" "💡" julia-latexsubs) +(puthash "\\:anger:" "💢" julia-latexsubs) +(puthash "\\:bomb:" "💣" julia-latexsubs) +(puthash "\\:zzz:" "💤" julia-latexsubs) +(puthash "\\:boom:" "💥" julia-latexsubs) +(puthash "\\:sweat_drops:" "💦" julia-latexsubs) +(puthash "\\:droplet:" "💧" julia-latexsubs) +(puthash "\\:dash:" "💨" julia-latexsubs) +(puthash "\\:hankey:" "💩" julia-latexsubs) +(puthash "\\:muscle:" "💪" julia-latexsubs) +(puthash "\\:dizzy:" "💫" julia-latexsubs) +(puthash "\\:speech_balloon:" "💬" julia-latexsubs) +(puthash "\\:thought_balloon:" "💭" julia-latexsubs) +(puthash "\\:white_flower:" "💮" julia-latexsubs) +(puthash "\\:100:" "💯" julia-latexsubs) +(puthash "\\:moneybag:" "💰" julia-latexsubs) +(puthash "\\:currency_exchange:" "💱" julia-latexsubs) +(puthash "\\:heavy_dollar_sign:" "💲" julia-latexsubs) +(puthash "\\:credit_card:" "💳" julia-latexsubs) +(puthash "\\:yen:" "💴" julia-latexsubs) +(puthash "\\:dollar:" "💵" julia-latexsubs) +(puthash "\\:euro:" "💶" julia-latexsubs) +(puthash "\\:pound:" "💷" julia-latexsubs) +(puthash "\\:money_with_wings:" "💸" julia-latexsubs) +(puthash "\\:chart:" "💹" julia-latexsubs) +(puthash "\\:seat:" "💺" julia-latexsubs) +(puthash "\\:computer:" "💻" julia-latexsubs) +(puthash "\\:briefcase:" "💼" julia-latexsubs) +(puthash "\\:minidisc:" "💽" julia-latexsubs) +(puthash "\\:floppy_disk:" "💾" julia-latexsubs) +(puthash "\\:cd:" "💿" julia-latexsubs) +(puthash "\\:dvd:" "📀" julia-latexsubs) +(puthash "\\:file_folder:" "📁" julia-latexsubs) +(puthash "\\:open_file_folder:" "📂" julia-latexsubs) +(puthash "\\:page_with_curl:" "📃" julia-latexsubs) +(puthash "\\:page_facing_up:" "📄" julia-latexsubs) +(puthash "\\:date:" "📅" julia-latexsubs) +(puthash "\\:calendar:" "📆" julia-latexsubs) +(puthash "\\:card_index:" "📇" julia-latexsubs) +(puthash "\\:chart_with_upwards_trend:" "📈" julia-latexsubs) +(puthash "\\:chart_with_downwards_trend:" "📉" julia-latexsubs) +(puthash "\\:bar_chart:" "📊" julia-latexsubs) +(puthash "\\:clipboard:" "📋" julia-latexsubs) +(puthash "\\:pushpin:" "📌" julia-latexsubs) +(puthash "\\:round_pushpin:" "📍" julia-latexsubs) +(puthash "\\:paperclip:" "📎" julia-latexsubs) +(puthash "\\:straight_ruler:" "📏" julia-latexsubs) +(puthash "\\:triangular_ruler:" "📐" julia-latexsubs) +(puthash "\\:bookmark_tabs:" "📑" julia-latexsubs) +(puthash "\\:ledger:" "📒" julia-latexsubs) +(puthash "\\:notebook:" "📓" julia-latexsubs) +(puthash "\\:notebook_with_decorative_cover:" "📔" julia-latexsubs) +(puthash "\\:closed_book:" "📕" julia-latexsubs) +(puthash "\\:book:" "📖" julia-latexsubs) +(puthash "\\:green_book:" "📗" julia-latexsubs) +(puthash "\\:blue_book:" "📘" julia-latexsubs) +(puthash "\\:orange_book:" "📙" julia-latexsubs) +(puthash "\\:books:" "📚" julia-latexsubs) +(puthash "\\:name_badge:" "📛" julia-latexsubs) +(puthash "\\:scroll:" "📜" julia-latexsubs) +(puthash "\\:memo:" "📝" julia-latexsubs) +(puthash "\\:telephone_receiver:" "📞" julia-latexsubs) +(puthash "\\:pager:" "📟" julia-latexsubs) +(puthash "\\:fax:" "📠" julia-latexsubs) +(puthash "\\:satellite:" "📡" julia-latexsubs) +(puthash "\\:loudspeaker:" "📢" julia-latexsubs) +(puthash "\\:mega:" "📣" julia-latexsubs) +(puthash "\\:outbox_tray:" "📤" julia-latexsubs) +(puthash "\\:inbox_tray:" "📥" julia-latexsubs) +(puthash "\\:package:" "📦" julia-latexsubs) +(puthash "\\:e-mail:" "📧" julia-latexsubs) +(puthash "\\:incoming_envelope:" "📨" julia-latexsubs) +(puthash "\\:envelope_with_arrow:" "📩" julia-latexsubs) +(puthash "\\:mailbox_closed:" "📪" julia-latexsubs) +(puthash "\\:mailbox:" "📫" julia-latexsubs) +(puthash "\\:mailbox_with_mail:" "📬" julia-latexsubs) +(puthash "\\:mailbox_with_no_mail:" "📭" julia-latexsubs) +(puthash "\\:postbox:" "📮" julia-latexsubs) +(puthash "\\:postal_horn:" "📯" julia-latexsubs) +(puthash "\\:newspaper:" "📰" julia-latexsubs) +(puthash "\\:iphone:" "📱" julia-latexsubs) +(puthash "\\:calling:" "📲" julia-latexsubs) +(puthash "\\:vibration_mode:" "📳" julia-latexsubs) +(puthash "\\:mobile_phone_off:" "📴" julia-latexsubs) +(puthash "\\:no_mobile_phones:" "📵" julia-latexsubs) +(puthash "\\:signal_strength:" "📶" julia-latexsubs) +(puthash "\\:camera:" "📷" julia-latexsubs) +(puthash "\\:video_camera:" "📹" julia-latexsubs) +(puthash "\\:tv:" "📺" julia-latexsubs) +(puthash "\\:radio:" "📻" julia-latexsubs) +(puthash "\\:vhs:" "📼" julia-latexsubs) +(puthash "\\:twisted_rightwards_arrows:" "🔀" julia-latexsubs) +(puthash "\\:repeat:" "🔁" julia-latexsubs) +(puthash "\\:repeat_one:" "🔂" julia-latexsubs) +(puthash "\\:arrows_clockwise:" "🔃" julia-latexsubs) +(puthash "\\:arrows_counterclockwise:" "🔄" julia-latexsubs) +(puthash "\\:low_brightness:" "🔅" julia-latexsubs) +(puthash "\\:high_brightness:" "🔆" julia-latexsubs) +(puthash "\\:mute:" "🔇" julia-latexsubs) +(puthash "\\:speaker:" "🔈" julia-latexsubs) +(puthash "\\:sound:" "🔉" julia-latexsubs) +(puthash "\\:loud_sound:" "🔊" julia-latexsubs) +(puthash "\\:battery:" "🔋" julia-latexsubs) +(puthash "\\:electric_plug:" "🔌" julia-latexsubs) +(puthash "\\:mag:" "🔍" julia-latexsubs) +(puthash "\\:mag_right:" "🔎" julia-latexsubs) +(puthash "\\:lock_with_ink_pen:" "🔏" julia-latexsubs) +(puthash "\\:closed_lock_with_key:" "🔐" julia-latexsubs) +(puthash "\\:key:" "🔑" julia-latexsubs) +(puthash "\\:lock:" "🔒" julia-latexsubs) +(puthash "\\:unlock:" "🔓" julia-latexsubs) +(puthash "\\:bell:" "🔔" julia-latexsubs) +(puthash "\\:no_bell:" "🔕" julia-latexsubs) +(puthash "\\:bookmark:" "🔖" julia-latexsubs) +(puthash "\\:link:" "🔗" julia-latexsubs) +(puthash "\\:radio_button:" "🔘" julia-latexsubs) +(puthash "\\:back:" "🔙" julia-latexsubs) +(puthash "\\:end:" "🔚" julia-latexsubs) +(puthash "\\:on:" "🔛" julia-latexsubs) +(puthash "\\:soon:" "🔜" julia-latexsubs) +(puthash "\\:top:" "🔝" julia-latexsubs) +(puthash "\\:underage:" "🔞" julia-latexsubs) +(puthash "\\:keycap_ten:" "🔟" julia-latexsubs) +(puthash "\\:capital_abcd:" "🔠" julia-latexsubs) +(puthash "\\:abcd:" "🔡" julia-latexsubs) +(puthash "\\:1234:" "🔢" julia-latexsubs) +(puthash "\\:symbols:" "🔣" julia-latexsubs) +(puthash "\\:abc:" "🔤" julia-latexsubs) +(puthash "\\:fire:" "🔥" julia-latexsubs) +(puthash "\\:flashlight:" "🔦" julia-latexsubs) +(puthash "\\:wrench:" "🔧" julia-latexsubs) +(puthash "\\:hammer:" "🔨" julia-latexsubs) +(puthash "\\:nut_and_bolt:" "🔩" julia-latexsubs) +(puthash "\\:hocho:" "🔪" julia-latexsubs) +(puthash "\\:gun:" "🔫" julia-latexsubs) +(puthash "\\:microscope:" "🔬" julia-latexsubs) +(puthash "\\:telescope:" "🔭" julia-latexsubs) +(puthash "\\:crystal_ball:" "🔮" julia-latexsubs) +(puthash "\\:six_pointed_star:" "🔯" julia-latexsubs) +(puthash "\\:beginner:" "🔰" julia-latexsubs) +(puthash "\\:trident:" "🔱" julia-latexsubs) +(puthash "\\:black_square_button:" "🔲" julia-latexsubs) +(puthash "\\:white_square_button:" "🔳" julia-latexsubs) +(puthash "\\:red_circle:" "🔴" julia-latexsubs) +(puthash "\\:large_blue_circle:" "🔵" julia-latexsubs) +(puthash "\\:large_orange_diamond:" "🔶" julia-latexsubs) +(puthash "\\:large_blue_diamond:" "🔷" julia-latexsubs) +(puthash "\\:small_orange_diamond:" "🔸" julia-latexsubs) +(puthash "\\:small_blue_diamond:" "🔹" julia-latexsubs) +(puthash "\\:small_red_triangle:" "🔺" julia-latexsubs) +(puthash "\\:small_red_triangle_down:" "🔻" julia-latexsubs) +(puthash "\\:arrow_up_small:" "🔼" julia-latexsubs) +(puthash "\\:arrow_down_small:" "🔽" julia-latexsubs) +(puthash "\\:clock1:" "🕐" julia-latexsubs) +(puthash "\\:clock2:" "🕑" julia-latexsubs) +(puthash "\\:clock3:" "🕒" julia-latexsubs) +(puthash "\\:clock4:" "🕓" julia-latexsubs) +(puthash "\\:clock5:" "🕔" julia-latexsubs) +(puthash "\\:clock6:" "🕕" julia-latexsubs) +(puthash "\\:clock7:" "🕖" julia-latexsubs) +(puthash "\\:clock8:" "🕗" julia-latexsubs) +(puthash "\\:clock9:" "🕘" julia-latexsubs) +(puthash "\\:clock10:" "🕙" julia-latexsubs) +(puthash "\\:clock11:" "🕚" julia-latexsubs) +(puthash "\\:clock12:" "🕛" julia-latexsubs) +(puthash "\\:clock130:" "🕜" julia-latexsubs) +(puthash "\\:clock230:" "🕝" julia-latexsubs) +(puthash "\\:clock330:" "🕞" julia-latexsubs) +(puthash "\\:clock430:" "🕟" julia-latexsubs) +(puthash "\\:clock530:" "🕠" julia-latexsubs) +(puthash "\\:clock630:" "🕡" julia-latexsubs) +(puthash "\\:clock730:" "🕢" julia-latexsubs) +(puthash "\\:clock830:" "🕣" julia-latexsubs) +(puthash "\\:clock930:" "🕤" julia-latexsubs) +(puthash "\\:clock1030:" "🕥" julia-latexsubs) +(puthash "\\:clock1130:" "🕦" julia-latexsubs) +(puthash "\\:clock1230:" "🕧" julia-latexsubs) +(puthash "\\:mount_fuji:" "🗻" julia-latexsubs) +(puthash "\\:tokyo_tower:" "🗼" julia-latexsubs) +(puthash "\\:statue_of_liberty:" "🗽" julia-latexsubs) +(puthash "\\:japan:" "🗾" julia-latexsubs) +(puthash "\\:moyai:" "🗿" julia-latexsubs) +(puthash "\\:grinning:" "😀" julia-latexsubs) +(puthash "\\:grin:" "😁" julia-latexsubs) +(puthash "\\:joy:" "😂" julia-latexsubs) +(puthash "\\:smiley:" "😃" julia-latexsubs) +(puthash "\\:smile:" "😄" julia-latexsubs) +(puthash "\\:sweat_smile:" "😅" julia-latexsubs) +(puthash "\\:laughing:" "😆" julia-latexsubs) +(puthash "\\:innocent:" "😇" julia-latexsubs) +(puthash "\\:smiling_imp:" "😈" julia-latexsubs) +(puthash "\\:wink:" "😉" julia-latexsubs) +(puthash "\\:blush:" "😊" julia-latexsubs) +(puthash "\\:yum:" "😋" julia-latexsubs) +(puthash "\\:relieved:" "😌" julia-latexsubs) +(puthash "\\:heart_eyes:" "😍" julia-latexsubs) +(puthash "\\:sunglasses:" "😎" julia-latexsubs) +(puthash "\\:smirk:" "😏" julia-latexsubs) +(puthash "\\:neutral_face:" "😐" julia-latexsubs) +(puthash "\\:expressionless:" "😑" julia-latexsubs) +(puthash "\\:unamused:" "😒" julia-latexsubs) +(puthash "\\:sweat:" "😓" julia-latexsubs) +(puthash "\\:pensive:" "😔" julia-latexsubs) +(puthash "\\:confused:" "😕" julia-latexsubs) +(puthash "\\:confounded:" "😖" julia-latexsubs) +(puthash "\\:kissing:" "😗" julia-latexsubs) +(puthash "\\:kissing_heart:" "😘" julia-latexsubs) +(puthash "\\:kissing_smiling_eyes:" "😙" julia-latexsubs) +(puthash "\\:kissing_closed_eyes:" "😚" julia-latexsubs) +(puthash "\\:stuck_out_tongue:" "😛" julia-latexsubs) +(puthash "\\:stuck_out_tongue_winking_eye:" "😜" julia-latexsubs) +(puthash "\\:stuck_out_tongue_closed_eyes:" "😝" julia-latexsubs) +(puthash "\\:disappointed:" "😞" julia-latexsubs) +(puthash "\\:worried:" "😟" julia-latexsubs) +(puthash "\\:angry:" "😠" julia-latexsubs) +(puthash "\\:rage:" "😡" julia-latexsubs) +(puthash "\\:cry:" "😢" julia-latexsubs) +(puthash "\\:persevere:" "😣" julia-latexsubs) +(puthash "\\:triumph:" "😤" julia-latexsubs) +(puthash "\\:disappointed_relieved:" "😥" julia-latexsubs) +(puthash "\\:frowning:" "😦" julia-latexsubs) +(puthash "\\:anguished:" "😧" julia-latexsubs) +(puthash "\\:fearful:" "😨" julia-latexsubs) +(puthash "\\:weary:" "😩" julia-latexsubs) +(puthash "\\:sleepy:" "😪" julia-latexsubs) +(puthash "\\:tired_face:" "😫" julia-latexsubs) +(puthash "\\:grimacing:" "😬" julia-latexsubs) +(puthash "\\:sob:" "😭" julia-latexsubs) +(puthash "\\:open_mouth:" "😮" julia-latexsubs) +(puthash "\\:hushed:" "😯" julia-latexsubs) +(puthash "\\:cold_sweat:" "😰" julia-latexsubs) +(puthash "\\:scream:" "😱" julia-latexsubs) +(puthash "\\:astonished:" "😲" julia-latexsubs) +(puthash "\\:flushed:" "😳" julia-latexsubs) +(puthash "\\:sleeping:" "😴" julia-latexsubs) +(puthash "\\:dizzy_face:" "😵" julia-latexsubs) +(puthash "\\:no_mouth:" "😶" julia-latexsubs) +(puthash "\\:mask:" "😷" julia-latexsubs) +(puthash "\\:smile_cat:" "😸" julia-latexsubs) +(puthash "\\:joy_cat:" "😹" julia-latexsubs) +(puthash "\\:smiley_cat:" "😺" julia-latexsubs) +(puthash "\\:heart_eyes_cat:" "😻" julia-latexsubs) +(puthash "\\:smirk_cat:" "😼" julia-latexsubs) +(puthash "\\:kissing_cat:" "😽" julia-latexsubs) +(puthash "\\:pouting_cat:" "😾" julia-latexsubs) +(puthash "\\:crying_cat_face:" "😿" julia-latexsubs) +(puthash "\\:scream_cat:" "🙀" julia-latexsubs) +(puthash "\\:no_good:" "🙅" julia-latexsubs) +(puthash "\\:ok_woman:" "🙆" julia-latexsubs) +(puthash "\\:bow:" "🙇" julia-latexsubs) +(puthash "\\:see_no_evil:" "🙈" julia-latexsubs) +(puthash "\\:hear_no_evil:" "🙉" julia-latexsubs) +(puthash "\\:speak_no_evil:" "🙊" julia-latexsubs) +(puthash "\\:raising_hand:" "🙋" julia-latexsubs) +(puthash "\\:raised_hands:" "🙌" julia-latexsubs) +(puthash "\\:person_frowning:" "🙍" julia-latexsubs) +(puthash "\\:person_with_pouting_face:" "🙎" julia-latexsubs) +(puthash "\\:pray:" "🙏" julia-latexsubs) +(puthash "\\:rocket:" "🚀" julia-latexsubs) +(puthash "\\:helicopter:" "🚁" julia-latexsubs) +(puthash "\\:steam_locomotive:" "🚂" julia-latexsubs) +(puthash "\\:railway_car:" "🚃" julia-latexsubs) +(puthash "\\:bullettrain_side:" "🚄" julia-latexsubs) +(puthash "\\:bullettrain_front:" "🚅" julia-latexsubs) +(puthash "\\:train2:" "🚆" julia-latexsubs) +(puthash "\\:metro:" "🚇" julia-latexsubs) +(puthash "\\:light_rail:" "🚈" julia-latexsubs) +(puthash "\\:station:" "🚉" julia-latexsubs) +(puthash "\\:tram:" "🚊" julia-latexsubs) +(puthash "\\:train:" "🚋" julia-latexsubs) +(puthash "\\:bus:" "🚌" julia-latexsubs) +(puthash "\\:oncoming_bus:" "🚍" julia-latexsubs) +(puthash "\\:trolleybus:" "🚎" julia-latexsubs) +(puthash "\\:busstop:" "🚏" julia-latexsubs) +(puthash "\\:minibus:" "🚐" julia-latexsubs) +(puthash "\\:ambulance:" "🚑" julia-latexsubs) +(puthash "\\:fire_engine:" "🚒" julia-latexsubs) +(puthash "\\:police_car:" "🚓" julia-latexsubs) +(puthash "\\:oncoming_police_car:" "🚔" julia-latexsubs) +(puthash "\\:taxi:" "🚕" julia-latexsubs) +(puthash "\\:oncoming_taxi:" "🚖" julia-latexsubs) +(puthash "\\:car:" "🚗" julia-latexsubs) +(puthash "\\:oncoming_automobile:" "🚘" julia-latexsubs) +(puthash "\\:blue_car:" "🚙" julia-latexsubs) +(puthash "\\:truck:" "🚚" julia-latexsubs) +(puthash "\\:articulated_lorry:" "🚛" julia-latexsubs) +(puthash "\\:tractor:" "🚜" julia-latexsubs) +(puthash "\\:monorail:" "🚝" julia-latexsubs) +(puthash "\\:mountain_railway:" "🚞" julia-latexsubs) +(puthash "\\:suspension_railway:" "🚟" julia-latexsubs) +(puthash "\\:mountain_cableway:" "🚠" julia-latexsubs) +(puthash "\\:aerial_tramway:" "🚡" julia-latexsubs) +(puthash "\\:ship:" "🚢" julia-latexsubs) +(puthash "\\:rowboat:" "🚣" julia-latexsubs) +(puthash "\\:speedboat:" "🚤" julia-latexsubs) +(puthash "\\:traffic_light:" "🚥" julia-latexsubs) +(puthash "\\:vertical_traffic_light:" "🚦" julia-latexsubs) +(puthash "\\:construction:" "🚧" julia-latexsubs) +(puthash "\\:rotating_light:" "🚨" julia-latexsubs) +(puthash "\\:triangular_flag_on_post:" "🚩" julia-latexsubs) +(puthash "\\:door:" "🚪" julia-latexsubs) +(puthash "\\:no_entry_sign:" "🚫" julia-latexsubs) +(puthash "\\:smoking:" "🚬" julia-latexsubs) +(puthash "\\:no_smoking:" "🚭" julia-latexsubs) +(puthash "\\:put_litter_in_its_place:" "🚮" julia-latexsubs) +(puthash "\\:do_not_litter:" "🚯" julia-latexsubs) +(puthash "\\:potable_water:" "🚰" julia-latexsubs) +(puthash "\\:non-potable_water:" "🚱" julia-latexsubs) +(puthash "\\:bike:" "🚲" julia-latexsubs) +(puthash "\\:no_bicycles:" "🚳" julia-latexsubs) +(puthash "\\:bicyclist:" "🚴" julia-latexsubs) +(puthash "\\:mountain_bicyclist:" "🚵" julia-latexsubs) +(puthash "\\:walking:" "🚶" julia-latexsubs) +(puthash "\\:no_pedestrians:" "🚷" julia-latexsubs) +(puthash "\\:children_crossing:" "🚸" julia-latexsubs) +(puthash "\\:mens:" "🚹" julia-latexsubs) +(puthash "\\:womens:" "🚺" julia-latexsubs) +(puthash "\\:restroom:" "🚻" julia-latexsubs) +(puthash "\\:baby_symbol:" "🚼" julia-latexsubs) +(puthash "\\:toilet:" "🚽" julia-latexsubs) +(puthash "\\:wc:" "🚾" julia-latexsubs) +(puthash "\\:shower:" "🚿" julia-latexsubs) +(puthash "\\:bath:" "🛀" julia-latexsubs) +(puthash "\\:bathtub:" "🛁" julia-latexsubs) +(puthash "\\:passport_control:" "🛂" julia-latexsubs) +(puthash "\\:customs:" "🛃" julia-latexsubs) +(puthash "\\:baggage_claim:" "🛄" julia-latexsubs) +(puthash "\\:left_luggage:" "🛅" julia-latexsubs) diff --git a/elpa/julia-mode-20191002.1352/julia-mode-autoloads.el b/elpa/julia-mode-20191002.1352/julia-mode-autoloads.el new file mode 100644 index 00000000..268089ab --- /dev/null +++ b/elpa/julia-mode-20191002.1352/julia-mode-autoloads.el @@ -0,0 +1,37 @@ +;;; julia-mode-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "julia-mode" "julia-mode.el" (23997 31535 905690 +;;;;;; 231000)) +;;; Generated autoloads from julia-mode.el + +(add-to-list 'auto-mode-alist '("\\.jl\\'" . julia-mode)) + +(autoload 'julia-mode "julia-mode" "\ +Major mode for editing julia code. + +\(fn)" t nil) + +(autoload 'inferior-julia "julia-mode" "\ +Run an inferior instance of `julia' inside Emacs. + +\(fn)" t nil) + +(defalias 'run-julia #'inferior-julia "\ +Run an inferior instance of `julia' inside Emacs.") + +;;;*** + +;;;### (autoloads nil nil ("julia-latexsubs.el" "julia-mode-pkg.el") +;;;;;; (23997 31535 909479 733000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; julia-mode-autoloads.el ends here diff --git a/elpa/julia-mode-20191002.1352/julia-mode-pkg.el b/elpa/julia-mode-20191002.1352/julia-mode-pkg.el new file mode 100644 index 00000000..66c59f67 --- /dev/null +++ b/elpa/julia-mode-20191002.1352/julia-mode-pkg.el @@ -0,0 +1,6 @@ +(define-package "julia-mode" "20191002.1352" "Major mode for editing Julia source code" 'nil :keywords + '("languages") + :url "https://github.com/JuliaLang/julia") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/julia-mode-20191002.1352/julia-mode.el b/elpa/julia-mode-20191002.1352/julia-mode.el new file mode 100644 index 00000000..32635074 --- /dev/null +++ b/elpa/julia-mode-20191002.1352/julia-mode.el @@ -0,0 +1,946 @@ +;;; julia-mode.el --- Major mode for editing Julia source code + +;; Copyright (C) 2009-2014 Julia contributors +;; URL: https://github.com/JuliaLang/julia +;; Version: 0.3 +;; Keywords: languages + +;;; Usage: +;; Put the following code in your .emacs, site-load.el, or other relevant file +;; (add-to-list 'load-path "path-to-julia-mode") +;; (require 'julia-mode) + +;;; Commentary: +;; This is the official Emacs mode for editing Julia programs. + +;;; License: +;; Permission is hereby granted, free of charge, to any person obtaining +;; a copy of this software and associated documentation files (the +;; "Software"), to deal in the Software without restriction, including +;; without limitation the rights to use, copy, modify, merge, publish, +;; distribute, sublicense, and/or sell copies of the Software, and to +;; permit persons to whom the Software is furnished to do so, subject to +;; the following conditions: +;; +;; The above copyright notice and this permission notice shall be +;; included in all copies or substantial portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +;;; Code: + +;; We can't use cl-lib whilst supporting Emacs 23 users who don't use +;; ELPA. +(with-no-warnings + (require 'cl)) ;; incf, decf, plusp + +(defvar julia-mode-hook nil) + +(defgroup julia () + "Major mode for the julia programming language." + :group 'languages + :prefix "julia-") + +(defcustom julia-indent-offset 4 + "Number of spaces per indentation level." + :type 'integer + :group 'julia) + +(defface julia-macro-face + '((t :inherit font-lock-preprocessor-face)) + "Face for Julia macro invocations." + :group 'julia-mode) + +(defface julia-quoted-symbol-face + '((t :inherit font-lock-preprocessor-face)) + "Face for quoted Julia symbols, e.g. :foo." + :group 'julia-mode) + + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.jl\\'" . julia-mode)) + +;; define ignore-errors macro if it isn't present +;; (necessary for emacs 22 compatibility) +(when (not (fboundp 'ignore-errors)) + (defmacro ignore-errors (body) `(condition-case nil ,body (error nil)))) + +(defun julia--regexp-opt (strings &optional paren) + "Emacs 23 provides `regexp-opt', but it does not support PAREN taking the value 'symbols. +This function provides equivalent functionality, but makes no efforts to optimise the regexp." + (cond + ((>= emacs-major-version 24) + (regexp-opt strings paren)) + ((not (eq paren 'symbols)) + (regexp-opt strings paren)) + ((null strings) + "") + ('t + (rx-to-string `(seq symbol-start (or ,@strings) symbol-end))))) + +(defvar julia-mode-syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?_ "_" table) + (modify-syntax-entry ?@ "_" table) + (modify-syntax-entry ?! "_" table) + (modify-syntax-entry ?# "< 14" table) ; # single-line and multiline start + (modify-syntax-entry ?= ". 23bn" table) + (modify-syntax-entry ?\n ">" table) ; \n single-line comment end + (modify-syntax-entry ?\{ "(} " table) + (modify-syntax-entry ?\} "){ " table) + (modify-syntax-entry ?\[ "(] " table) + (modify-syntax-entry ?\] ")[ " table) + (modify-syntax-entry ?\( "() " table) + (modify-syntax-entry ?\) ")( " table) + ;; Here, we treat ' as punctuation (when it's used for transpose), + ;; see our use of `julia-char-regex' for handling ' as a character + ;; delimiter + (modify-syntax-entry ?' "." table) + (modify-syntax-entry ?\" "\"" table) + (modify-syntax-entry ?` "\"" table) + (modify-syntax-entry ?\\ "\\" table) + + (modify-syntax-entry ?. "." table) + (modify-syntax-entry ?? "." table) + (modify-syntax-entry ?$ "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?* "." table) + (modify-syntax-entry ?/ "." table) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?% "." table) + + (modify-syntax-entry ?′ "w" table) ; \prime is a word constituent + table) + "Syntax table for `julia-mode'.") + +(eval-when-compile + (defconst julia-char-regex + (rx (or (any "-" ";" "\\" "^" "!" "|" "?" "*" "<" "%" "," "=" ">" "+" "/" "&" "$" "~" ":") + (syntax open-parenthesis) + (syntax whitespace) + bol) + (group "'") + (group + (or (repeat 0 8 (not (any "'"))) (not (any "\\")) + "\\\\")) + (group "'")))) + +(defconst julia-hanging-operator-regexp + ;; taken from julia-parser.scm + (concat "^[^#\n]+ " + (regexp-opt + '( ;; conditional + "?" + ;; assignment + "=" ":=" "+=" "-=" "*=" "/=" "//=" ".//=" ".*=" "./=" "\\=" ".\\=" + "^=" ".^=" "÷=" ".÷=" "%=" ".%=" "|=" "&=" "$=" "=>" "<<=" ">>=" + ">>>=" "~" ".+=" ".-=" + ;; arrow + "--" "-->" "←" "→" "↔" "↚" "↛" "↠" "↣" "↦" "↮" "⇎" "⇏" "⇒" "⇔" "⇴" + "⇶" "⇷" "⇸" "⇹" "⇺" "⇻" "⇼" "⇽" "⇾" "⇿" "⟵" "⟶" "⟷" "⟷" "⟹" + "⟺" "⟻" "⟼" "⟽" "⟾" "⟿" "⤀" "⤁" "⤂" "⤃" "⤄" "⤅" "⤆" "⤇" "⤌" + "⤍" "⤎" "⤏" "⤐" "⤑" "⤔" "⤕" "⤖" "⤗" "⤘" "⤝" "⤞" "⤟" "⤠" "⥄" "⥅" + "⥆" "⥇" "⥈" "⥊" "⥋" "⥎" "⥐" "⥒" "⥓" "⥖" "⥗" "⥚" "⥛" "⥞" "⥟" "⥢" + "⥤" "⥦" "⥧" "⥨" "⥩" "⥪" "⥫" "⥬" "⥭" "⥰" "⧴" "⬱" "⬰" "⬲" "⬳" "⬴" + "⬵" "⬶" "⬷" "⬸" "⬹" "⬺" "⬻" "⬼" "⬽" "⬾" "⬿" "⭀" "⭁" "⭂" "⭃" "⭄" + "⭇" "⭈" "⭉" "⭊" "⭋" "⭌" "←" "→" + ;; or and and + "&&" "||" + ;; comparison + ">" "<" ">=" "≥" "<=" "≤" "==" "===" "≡" "!=" "≠" "!==" "≢" ".>" + ".<" ".>=" ".≥" ".<=" ".≤" ".==" ".!=" ".≠" ".=" ".!" "<:" ">:" "∈" + "∉" "∋" "∌" "⊆" "⊈" "⊂" "⊄" "⊊" "∝" "∊" "∍" "∥" "∦" "∷" "∺" "∻" "∽" + "∾" "≁" "≃" "≄" "≅" "≆" "≇" "≈" "≉" "≊" "≋" "≌" "≍" "≎" "≐" "≑" "≒" + "≓" "≔" "≕" "≖" "≗" "≘" "≙" "≚" "≛" "≜" "≝" "≞" "≟" "≣" "≦" "≧" "≨" + "≩" "≪" "≫" "≬" "≭" "≮" "≯" "≰" "≱" "≲" "≳" "≴" "≵" "≶" "≷" "≸" "≹" + "≺" "≻" "≼" "≽" "≾" "≿" "⊀" "⊁" "⊃" "⊅" "⊇" "⊉" "⊋" "⊏" "⊐" "⊑" "⊒" + "⊜" "⊩" "⊬" "⊮" "⊰" "⊱" "⊲" "⊳" "⊴" "⊵" "⊶" "⊷" "⋍" "⋐" "⋑" "⋕" "⋖" + "⋗" "⋘" "⋙" "⋚" "⋛" "⋜" "⋝" "⋞" "⋟" "⋠" "⋡" "⋢" "⋣" "⋤" "⋥" "⋦" "⋧" + "⋨" "⋩" "⋪" "⋫" "⋬" "⋭" "⋲" "⋳" "⋴" "⋵" "⋶" "⋷" "⋸" "⋹" "⋺" "⋻" "⋼" + "⋽" "⋾" "⋿" "⟈" "⟉" "⟒" "⦷" "⧀" "⧁" "⧡" "⧣" "⧤" "⧥" "⩦" "⩧" "⩪" "⩫" + "⩬" "⩭" "⩮" "⩯" "⩰" "⩱" "⩲" "⩳" "⩴" "⩵" "⩶" "⩷" "⩸" "⩹" "⩺" "⩻" "⩼" + "⩽" "⩾" "⩿" "⪀" "⪁" "⪂" "⪃" "⪄" "⪅" "⪆" "⪇" "⪈" "⪉" "⪊" "⪋" "⪌" "⪍" + "⪎" "⪏" "⪐" "⪑" "⪒" "⪓" "⪔" "⪕" "⪖" "⪗" "⪘" "⪙" "⪚" "⪛" "⪜" "⪝" "⪞" + "⪟" "⪠" "⪡" "⪢" "⪣" "⪤" "⪥" "⪦" "⪧" "⪨" "⪩" "⪪" "⪫" "⪬" "⪭" "⪮" "⪯" + "⪰" "⪱" "⪲" "⪳" "⪴" "⪵" "⪶" "⪷" "⪸" "⪹" "⪺" "⪻" "⪼" "⪽" "⪾" "⪿" "⫀" + "⫁" "⫂" "⫃" "⫄" "⫅" "⫆" "⫇" "⫈" "⫉" "⫊" "⫋" "⫌" "⫍" "⫎" "⫏" "⫐" "⫑" + "⫒" "⫓" "⫔" "⫕" "⫖" "⫗" "⫘" "⫙" "⫷" "⫸" "⫹" "⫺" "⊢" "⊣" + ;; pipe, colon + "|>" "<|" ":" ".." + ;; plus + "+" "-" "⊕" "⊖" "⊞" "⊟" ".+" ".-" "++" "|" "∪" "∨" "$" "⊔" "±" "∓" + "∔" "∸" "≂" "≏" "⊎" "⊻" "⊽" "⋎" "⋓" "⧺" "⧻" "⨈" "⨢" "⨣" "⨤" "⨥" "⨦" + "⨧" "⨨" "⨩" "⨪" "⨫" "⨬" "⨭" "⨮" "⨹" "⨺" "⩁" "⩂" "⩅" "⩊" "⩌" "⩏" "⩐" + "⩒" "⩔" "⩖" "⩗" "⩛" "⩝" "⩡" "⩢" "⩣" + ;; bitshift + "<<" ">>" ">>>" ".<<" ".>>" ".>>>" + ;; times + "*" "/" "./" "÷" ".÷" "%" "⋅" "∘" "×" ".%" ".*" "\\" + ".\\" "&" "∩" "∧" "⊗" "⊘" "⊙" "⊚" "⊛" "⊠" "⊡" "⊓" "∗" "∙" "∤" "⅋" + "≀" "⊼" "⋄" "⋆" "⋇" "⋉" "⋊" "⋋" "⋌" "⋏" "⋒" "⟑" "⦸" "⦼" "⦾" "⦿" "⧶" + "⧷" "⨇" "⨰" "⨱" "⨲" "⨳" "⨴" "⨵" "⨶" "⨷" "⨸" "⨻" "⨼" "⨽" "⩀" "⩃" "⩄" + "⩋" "⩍" "⩎" "⩑" "⩓" "⩕" "⩘" "⩚" "⩜" "⩞" "⩟" "⩠" "⫛" "⊍" "▷" "⨝" "⟕" + "⟖" "⟗" + ;; rational + "//" ".//" + ;; power + "^" ".^" "↑" "↓" "⇵" "⟰" "⟱" "⤈" "⤉" "⤊" "⤋" "⤒" "⤓" "⥉" "⥌" "⥍" + "⥏" "⥑" "⥔" "⥕" "⥘" "⥙" "⥜" "⥝" "⥠" "⥡" "⥣" "⥥" "⥮" "⥯" "↑" "↓" + ;; decl, dot + "::" ".")) + (regexp-opt '(" #" " \n" "#" "\n")))) + +(defconst julia-triple-quoted-string-regex + ;; We deliberately put a group on the first and last delimiter, so + ;; we can mark these as string delimiters for font-lock. + (rx (group "\"") + (group "\"\"" + ;; After the delimiter, we're a sequence of + ;; non-backslashes or blackslashes paired with something. + (*? (or (not (any "\\")) + (seq "\\" anything))) + "\"\"") + (group "\""))) + +(defconst julia-unquote-regex + "\\(\\s(\\|\\s-\\|-\\|[,%=<>\\+*/?&|!\\^~\\\\;:]\\|^\\)\\($[a-zA-Z0-9_]+\\)") + +(defconst julia-forloop-in-regex + "for +.*[^ +].* \\(in\\)\\(\\s-\\|$\\)+") + +(defconst julia-function-regex + (rx line-start (* (or space "@inline" "@noinline")) symbol-start + "function" + (1+ space) + ;; Don't highlight module names in function declarations: + (* (seq (1+ (or word (syntax symbol))) ".")) + ;; The function name itself + (group (1+ (or word (syntax symbol)))))) + +(defconst julia-function-assignment-regex + (rx line-start (* (or space "@inline" "@noinline")) symbol-start + (* (seq (1+ (or word (syntax symbol))) ".")) ; module name + (group (1+ (or word (syntax symbol)))) + (? "{" (* (not (any "}"))) "}") + "(" (* (or + (seq "(" (* (not (any "(" ")"))) ")") + (not (any "(" ")")))) + ")" + (* space) + (? "::" (* space) (1+ (not (any space)))) + (* space) + (* (seq "where" (or "{" (+ space)) (+ (not (any "="))))) + "=" + (not (any "=")))) + +(defconst julia-type-regex + (rx symbol-start (or ;;"immutable" "type" ;; remove after 0.6 + "abstract type" "primitive type" "struct" "mutable struct") + (1+ space) (group (1+ (or word (syntax symbol)))))) + +(defconst julia-type-annotation-regex + (rx "::" (0+ space) (group (1+ (or word (syntax symbol)))))) + +;;(defconst julia-type-parameter-regex +;; (rx symbol-start (1+ (or (or word (syntax symbol)) ?_)) "{" (group (1+ (or (or word (syntax symbol)) ?_))) "}")) + +(defconst julia-subtype-regex + (rx "<:" (0+ space) (group (1+ (or word (syntax symbol)))) (0+ space) (or "\n" "{" "}" "end"))) + +(defconst julia-macro-regex + (rx symbol-start (group "@" (1+ (or word (syntax symbol)))))) + +(defconst julia-keyword-regex + (julia--regexp-opt + '("if" "else" "elseif" "while" "for" "begin" "end" "quote" + "try" "catch" "return" "local" "function" "macro" "ccall" + "finally" "break" "continue" "global" "where" + "module" "using" "import" "export" "const" "let" "do" "in" + "baremodule" + ;; "importall" ;; deprecated in 0.7 + ;; "immutable" "type" "bitstype" "abstract" "typealias" ;; removed in 1.0 + "abstract type" "primitive type" "struct" "mutable struct") + 'symbols)) + +(defconst julia-builtin-regex + (julia--regexp-opt + ;;'("error" "throw") + '() + 'symbols)) + +(defconst julia-builtin-types-regex + (julia--regexp-opt + '("Number" "Real" "BigInt" "Integer" + "UInt" "UInt8" "UInt16" "UInt32" "UInt64" "UInt128" + "Int" "Int8" "Int16" "Int32" "Int64" "Int128" + "BigFloat" "AbstractFloat" "Float16" "Float32" "Float64" + ;;"Complex128" "Complex64" ;; replaced in 1.0 + "ComplexF32" "ComplexF64" + "Bool" + "Cuchar" "Cshort" "Cushort" "Cint" "Cuint" "Clonglong" "Culonglong" "Cintmax_t" "Cuintmax_t" + "Cfloat" "Cdouble" "Cptrdiff_t" "Cssize_t" "Csize_t" + "Cchar" "Clong" "Culong" "Cwchar_t" "Cvoid" + "Cstring" "Cwstring" ;; C strings made of ordinary and wide characters + "Char" "String" "SubString" + "Array" "DArray" "AbstractArray" "AbstractVector" "AbstractMatrix" "AbstractSparseMatrix" "SubArray" "StridedArray" "StridedVector" "StridedMatrix" "VecOrMat" "StridedVecOrMat" "DenseArray" "SparseMatrixCSC" "BitArray" + "AbstractRange" "OrdinalRange" "StepRange" "UnitRange" "FloatRange" + "Tuple" "NTuple" "Vararg" + "DataType" "Symbol" "Function" "Vector" "Matrix" "Union" "Type" "Any" "Complex" "AbstractString" "Ptr" "Nothing" "Exception" "Task" "Signed" "Unsigned" "AbstractDict" "Dict" "IO" "IOStream" "Rational" "Regex" "RegexMatch" "Set" "BitSet" "Expr" "WeakRef" "ObjectIdDict" + "AbstractRNG" "MersenneTwister" + ) + 'symbols)) + +(defconst julia-quoted-symbol-regex + ;; :foo and :foo2 are valid, but :123 is not. + (rx (or bol whitespace "(" "[" "," "=") + (group ":" (or letter (syntax symbol)) (0+ (or word (syntax symbol)))))) + +(defconst julia-font-lock-keywords + (list + ;; Ensure :: and <: aren't highlighted, so we don't confuse ::Foo with :foo. + ;; (in Emacs, keywords don't overlap). + (cons (rx (or "::" "<:")) ''default) + ;; Highlight quoted symbols before keywords, so :function is not + ;; highlighted as a keyword. + (list julia-quoted-symbol-regex 1 ''julia-quoted-symbol-face) + (cons julia-builtin-types-regex 'font-lock-type-face) + (cons julia-keyword-regex 'font-lock-keyword-face) + (cons julia-macro-regex ''julia-macro-face) + (cons + (julia--regexp-opt + '("true" "false" "C_NULL" "Inf" "NaN" "Inf32" "NaN32" "nothing" "undef") + 'symbols) + 'font-lock-constant-face) + (list julia-unquote-regex 2 'font-lock-constant-face) + (list julia-forloop-in-regex 1 'font-lock-keyword-face) + (list julia-function-regex 1 'font-lock-function-name-face) + (list julia-function-assignment-regex 1 'font-lock-function-name-face) + (list julia-type-regex 1 'font-lock-type-face) + (list julia-type-annotation-regex 1 'font-lock-type-face) + ;;(list julia-type-parameter-regex 1 'font-lock-type-face) + (list julia-subtype-regex 1 'font-lock-type-face) + (list julia-builtin-regex 1 'font-lock-builtin-face) + )) + +(defconst julia-block-start-keywords + (list "if" "while" "for" "begin" "try" "function" "let" "macro" + "quote" "do" "module" + ;; "immutable" "type" ;; remove after 0.6 + "abstract type" "primitive type" "struct" "mutable struct")) + +;; For keywords that begin a block without additional indentation +(defconst julia-block-start-keywords-no-indent + (list "module")) + +(defconst julia-block-end-keywords + (list "end" "else" "elseif" "catch" "finally")) + +(defun julia-stringify-triple-quote () + "Put `syntax-table' property on triple-quoted string delimiters. + +Based on `python-syntax-stringify'." + (let* ((string-start-pos (- (point) 3)) + (string-end-pos (point)) + (ppss (prog2 + (backward-char 3) + (syntax-ppss) + (forward-char 3))) + (in-comment (nth 4 ppss)) + (in-string (nth 8 ppss))) + (unless in-comment + (if in-string + ;; We're in a string, so this must be the closing triple-quote. + ;; Put | on the last " character. + (put-text-property (1- string-end-pos) string-end-pos + 'syntax-table (string-to-syntax "|")) + ;; We're not in a string, so this is the opening triple-quote. + ;; Put | on the first " character. + (put-text-property string-start-pos (1+ string-start-pos) + 'syntax-table (string-to-syntax "|")))))) + +(defconst julia-syntax-propertize-function + (unless (< emacs-major-version 24) + (syntax-propertize-rules + ("\"\"\"" + (0 (ignore (julia-stringify-triple-quote)))) + (julia-char-regex + (1 "\"") ; Treat ' as a string delimiter. + (2 ".") ; Don't highlight anything between. + (3 "\""))))) ; Treat the last " in """ as a string delimiter. + +(defun julia-in-comment (&optional syntax-ppss) + "Return non-nil if point is inside a comment using SYNTAX-PPSS. +Handles both single-line and multi-line comments." + (nth 4 (or syntax-ppss (syntax-ppss)))) + +(defun julia-in-string (&optional syntax-ppss) + "Return non-nil if point is inside a string using SYNTAX-PPSS. +Note this is Emacs' notion of what is highlighted as a string. +As a result, it is true inside \"foo\", `foo` and 'f'." + (nth 3 (or syntax-ppss (syntax-ppss)))) + +(defun julia-in-brackets () + "Return non-nil if point is inside square brackets." + (let ((start-pos (point)) + (open-count 0)) + ;; Count all the [ and ] characters on the current line. + (save-excursion + (beginning-of-line) + + (while (< (point) start-pos) + ;; Don't count [ or ] inside strings, characters or comments. + (unless (or (julia-in-string) (julia-in-comment)) + + (when (looking-at (rx "[")) + (incf open-count)) + (when (looking-at (rx "]")) + (decf open-count))) + + (forward-char 1))) + + ;; If we've opened more than we've closed, we're inside brackets. + (plusp open-count))) + +(defun julia-at-keyword (kw-list) + "Return the word at point if it matches any keyword in KW-LIST. +KW-LIST is a list of strings. The word at point is not considered +a keyword if used as a field name, X.word, or quoted, :word." + (and (or (= (point) 1) + (and (not (equal (char-before (point)) ?.)) + (not (equal (char-before (point)) ?:)))) + (not (looking-at "(")) ; handle "function(" when on ( + (member (current-word t) kw-list) + ;; 'end' is not a keyword when used for indexing, e.g. foo[end-2] + (or (not (equal (current-word t) "end")) + (not (julia-in-brackets))) + (not (julia-in-comment)))) + +;; if backward-sexp gives an error, move back 1 char to move over the '(' +(defun julia-safe-backward-sexp () + (if (condition-case nil (backward-sexp) (error t)) + (ignore-errors (backward-char)))) + +(defun julia-following-import-export-using () + "If the current line follows an `export` or `import` keyword +with valid syntax, return the position of the keyword, otherwise +`nil`. Works by stepping backwards through comma-separated +symbol, gives up when this is not true." + ;; Implementation accepts a single Module: right after the keyword, and saves + ;; the module name for future use, but does not enforce that `export` has no + ;; module name. + (let ((done nil) ; find keyword or give up + (module nil)) ; found "Module:" + (save-excursion + (beginning-of-line) + (while (and (not done) (< (point-min) (point))) + (julia-safe-backward-sexp) + (cond + ((looking-at (rx (or "import" "export" "using"))) + (setf done (point))) + ((looking-at (rx (group (* (or word (syntax symbol)))) (0+ space) ":")) + (if module + (setf done 'broken) + (setf module (match-string-no-properties 1)))) + ((looking-at (rx (* (or word (syntax symbol))) (0+ space) ",")) + (when module (setf done 'broken))) + (t (setf done 'broken))))) + (if (eq done 'broken) + nil + done))) + +(defun julia-last-open-block-pos (min) + "Return the position of the last open block, if one found. +Do not move back beyond position MIN." + (save-excursion + (let ((count 0)) + (while (not (or (> count 0) (<= (point) min))) + (julia-safe-backward-sexp) + (setq count + (cond ((julia-at-keyword julia-block-start-keywords) + (+ count 1)) + ((and (equal (current-word t) "end") + (not (julia-in-comment))) + (- count 1)) + (t count)))) + (if (> count 0) + (point) + nil)))) + +(defun julia-last-open-block (min) + "Move back and return indentation level for last open block. +Do not move back beyond MIN." + ;; Ensure MIN is not before the start of the buffer. + (setq min (max min (point-min))) + (let ((pos (julia-last-open-block-pos min))) + (and pos + (progn + (goto-char pos) + (+ julia-indent-offset (current-indentation)))))) + +(defsubst julia--safe-backward-char () + "Move back one character, but don't error if we're at the +beginning of the buffer." + (unless (eq (point) (point-min)) + (backward-char))) + +(defcustom julia-max-block-lookback 5000 + "When indenting, don't look back more than this +many characters to see if there are unclosed blocks. + +This variable has a moderate effect on indent performance if set too +high, but stops indenting in the middle of long blocks if set too low." + :type 'integer + :group 'julia) + +(defun julia-paren-indent () + "Return the column of the text following the innermost +containing paren before point, so we can align succeeding code +with it. Returns nil if we're not within nested parens." + (save-excursion + (beginning-of-line) + (let ((parser-state (syntax-ppss))) + (cond ((nth 3 parser-state) nil) ;; strings + ((= (nth 0 parser-state) 0) nil) ;; top level + (t + (ignore-errors ;; return nil if any of these movements fail + (beginning-of-line) + (skip-syntax-forward " ") + (let ((possibly-close-paren-point (point))) + (backward-up-list) + (let ((open-paren-point (point))) + (forward-char) + (skip-syntax-forward " ") + (if (eolp) + (progn + (up-list) + (backward-char) + (let ((paren-closed (= (point) possibly-close-paren-point))) + (goto-char open-paren-point) + (beginning-of-line) + (skip-syntax-forward " ") + (+ (current-column) + (if paren-closed + 0 + julia-indent-offset)))) + (current-column)))))))))) + +(defun julia-prev-line-skip-blank-or-comment () + "Move point to beginning of previous line skipping blank lines +and lines including only comments. Returns number of lines moved. +A return of -1 signals that we moved to the first line of +the (possibly narrowed) buffer, so there is nowhere else to go." + (catch 'result + (let ((moved 0) this-move) + (while t + (setq this-move (forward-line -1)) + (cond + ;; moved into comment or blank + ((and (= 0 this-move) + (or (looking-at-p "^\\s-*\\(?:#.*\\)*$") + (julia-in-comment))) + (incf moved)) + ;; success + ((= 0 this-move) + (throw 'result (1+ moved))) + ;; on first line and in comment + ((and (bobp) + (or (looking-at-p "^\\s-*\\(?:#.*\\)*$") + (julia-in-comment))) + (throw 'result -1)) + ((bobp) + (throw 'result moved)) + (t + (throw 'result 0))))))) + +(defun julia-indent-hanging () + "Calculate indentation for lines that follow \"hanging\" +operators (operators that end the previous line) as defined in +`julia-hanging-operator-regexp'. An assignment operator ending +the previous line increases the indent as do the other operators +unless another operator is found two lines up. Previous line +means previous line after skipping blank lines and lines with +only comments." + (let (prev-indent) + (save-excursion + (when (> (julia-prev-line-skip-blank-or-comment) 0) + (setq prev-indent (current-indentation)) + (when (looking-at-p julia-hanging-operator-regexp) + (if (and (> (julia-prev-line-skip-blank-or-comment) 0) + (looking-at-p julia-hanging-operator-regexp)) + ;; two preceding hanging operators => indent same as line + ;; above + prev-indent + ;; one preceding hanging operator => increase indent from line + ;; above + (+ julia-indent-offset prev-indent))))))) + +(defun julia-indent-in-string () + "Indentation inside strings with newlines is \"manual\", +meaning always increase indent on TAB and decrease on S-TAB." + (save-excursion + (beginning-of-line) + (when (julia-in-string) + (if (member this-command '(julia-latexsub-or-indent + ess-indent-or-complete)) + (+ julia-indent-offset (current-indentation)) + ;; return the current indentation to prevent other functions from + ;; indenting inside strings + (current-indentation))))) + +(defun julia-indent-import-export-using () + "Indent offset for lines that follow `import` or `export`, otherwise nil." + (when (julia-following-import-export-using) + julia-indent-offset)) + +(defun julia-indent-line () + "Indent current line of julia code." + (interactive) + (let* ((point-offset (- (current-column) (current-indentation)))) + (indent-line-to + (or + ;; note: if this first function returns nil the beginning of the line + ;; cannot be in a string + (julia-indent-in-string) + ;; If we're inside an open paren, indent to line up arguments. After this, + ;; we cannot be inside parens which includes brackets + (julia-paren-indent) + ;; indent due to hanging operators (lines ending in an operator) + (julia-indent-hanging) + ;; indent for import and export + (julia-indent-import-export-using) + ;; Indent according to how many nested blocks we are in. + (save-excursion + (beginning-of-line) + ;; jump out of any comments + (let ((state (syntax-ppss))) + (when (nth 4 state) + (goto-char (nth 8 state)))) + (forward-to-indentation 0) + (let ((endtok (julia-at-keyword julia-block-end-keywords)) + (last-open-block (julia-last-open-block (- (point) julia-max-block-lookback)))) + (max 0 (+ (or last-open-block 0) + (if (or endtok + (julia-at-keyword julia-block-start-keywords-no-indent)) + (- julia-indent-offset) 0))))))) + ;; Point is now at the beginning of indentation, restore it + ;; to its original position (relative to indentation). + (when (>= point-offset 0) + (move-to-column (+ (current-indentation) point-offset))))) + +(defalias 'julia-mode-prog-mode + (if (fboundp 'prog-mode) + 'prog-mode + 'fundamental-mode)) + + +;;; Navigation +;; based off python.el +(defconst julia-beginning-of-defun-regex + (concat julia-function-regex "\\|" + julia-function-assignment-regex "\\|" + "\\_") + "Regex matching beginning of Julia function or macro.") + +(defun julia-syntax-context-type (&optional syntax-ppss) + "Return the context type using SYNTAX-PPSS. +TYPE can be `comment', `string' or `paren'." + (let ((ppss (or syntax-ppss (syntax-ppss)))) + (cond + ((nth 8 ppss) (if (nth 4 ppss) 'comment 'string)) + ((nth 1 ppss) 'paren)))) + +(defsubst julia-syntax-comment-or-string-p (&optional syntax-ppss) + "Return non-nil if SYNTAX-PPSS is inside string or comment." + (nth 8 (or syntax-ppss (syntax-ppss)))) + +(defun julia-looking-at-beginning-of-defun (&optional syntax-ppss) + "Check if point is at `beginning-of-defun' using SYNTAX-PPSS." + (and (not (julia-syntax-comment-or-string-p (or syntax-ppss (syntax-ppss)))) + (save-excursion + (beginning-of-line 1) + (looking-at julia-beginning-of-defun-regex)))) + +(defun julia--beginning-of-defun (&optional arg) + "Internal implementation of `julia-beginning-of-defun'. +With positive ARG search backwards, else search forwards." + (when (or (null arg) (= arg 0)) (setq arg 1)) + (let* ((re-search-fn (if (> arg 0) + #'re-search-backward + #'re-search-forward)) + (line-beg-pos (line-beginning-position)) + (line-content-start (+ line-beg-pos (current-indentation))) + (pos (point-marker)) + (beg-indentation + (and (> arg 0) + (save-excursion + (while (and (not (julia-looking-at-beginning-of-defun)) + ;; f(x) = ... function bodies may span multiple lines + (or (and (julia-indent-hanging) + (forward-line -1)) + ;; inside dangling parameter list + (and (eq 'paren (julia-syntax-context-type)) + (backward-up-list)) + (julia-last-open-block (point-min))))) + (or (and (julia-looking-at-beginning-of-defun) + (+ (current-indentation) julia-indent-offset)) + 0)))) + (found + (progn + (when (and (< arg 0) + (julia-looking-at-beginning-of-defun)) + (end-of-line 1)) + (while (and (funcall re-search-fn + julia-beginning-of-defun-regex nil t) + (or (julia-syntax-comment-or-string-p) + ;; handle nested defuns when moving backwards + ;; by checking matching indentation + (and (> arg 0) + (not (= (current-indentation) 0)) + (>= (current-indentation) beg-indentation))))) + (and (julia-looking-at-beginning-of-defun) + (or (not (= (line-number-at-pos pos) + (line-number-at-pos))) + (and (>= (point) line-beg-pos) + (<= (point) line-content-start) + (> pos line-content-start))))))) + (if found + (or (beginning-of-line 1) (point)) + (and (goto-char pos) nil)))) + +(defun julia-beginning-of-defun (&optional arg) + "Move point to `beginning-of-defun'. +With positive ARG search backwards else search forward. +ARG nil or 0 defaults to 1. When searching backwards, +nested defuns are handled depending on current point position. +Return non-nil (point) if point moved to `beginning-of-defun'." + (when (or (null arg) (= arg 0)) (setq arg 1)) + (let ((found)) + (while (and (not (= arg 0)) + (let ((keep-searching-p + (julia--beginning-of-defun arg))) + (when (and keep-searching-p (null found)) + (setq found t)) + keep-searching-p)) + (setq arg (if (> arg 0) (1- arg) (1+ arg)))) + found)) + +(defun julia-end-of-defun (&optional arg) + "Move point to the end of the current function. +Return nil if point is not in a function, otherwise point." + (interactive) + (let ((beg-defun-indent) + (beg-pos (point))) + (when (or (julia-looking-at-beginning-of-defun) + (julia-beginning-of-defun 1) + (julia-beginning-of-defun -1)) + (beginning-of-line) + (if (looking-at-p julia-function-assignment-regex) + ;; f(x) = ... + (progn + ;; skip any dangling lines + (while (and (forward-line) + (not (eobp)) + (or (julia-indent-hanging) + ;; dangling closing paren + (and (eq 'paren (julia-syntax-context-type)) + (search-forward ")")))))) + ;; otherwise skip forward to matching indentation (not in string/comment) + (setq beg-defun-indent (current-indentation)) + (while (and (not (eobp)) + (forward-line 1) + (or (julia-syntax-comment-or-string-p) + (> (current-indentation) beg-defun-indent))))) + (end-of-line) + (point)))) + +;;; IMENU +(defvar julia-imenu-generic-expression + ;; don't use syntax classes, screws egrep + '(("Function (_)" "[ \t]*function[ \t]+\\(_[^ \t\n]*\\)" 1) + ("Function" "^[ \t]*function[ \t]+\\([^_][^\t\n]*\\)" 1) + ("Const" "[ \t]*const \\([^ \t\n]*\\)" 1) + ("Type" "^[ \t]*[a-zA-Z0-9_]*type[a-zA-Z0-9_]* \\([^ \t\n]*\\)" 1) + ("Require" " *\\(\\brequire\\)(\\([^ \t\n)]*\\)" 2) + ("Include" " *\\(\\binclude\\)(\\([^ \t\n)]*\\)" 2) + ;; ("Classes" "^.*setClass(\\(.*\\)," 1) + ;; ("Coercions" "^.*setAs(\\([^,]+,[^,]*\\)," 1) ; show from and to + ;; ("Generics" "^.*setGeneric(\\([^,]*\\)," 1) + ;; ("Methods" "^.*set\\(Group\\|Replace\\)?Method(\"\\(.+\\)\"," 2) + ;; ;;[ ]*\\(signature=\\)?(\\(.*,?\\)*\\)," 1) + ;; ;; + ;; ;;("Other" "^\\(.+\\)\\s-*<-[ \t\n]*[^\\(function\\|read\\|.*data\.frame\\)]" 1) + ;; ("Package" "^.*\\(library\\|require\\)(\\(.*\\)," 2) + ;; ("Data" "^\\(.+\\)\\s-*<-[ \t\n]*\\(read\\|.*data\.frame\\).*(" 1))) + )) + +;;;###autoload +(define-derived-mode julia-mode julia-mode-prog-mode "Julia" + "Major mode for editing julia code." + (set-syntax-table julia-mode-syntax-table) + (set (make-local-variable 'comment-start) "# ") + (set (make-local-variable 'comment-start-skip) "#+\\s-*") + (set (make-local-variable 'font-lock-defaults) '(julia-font-lock-keywords)) + (if (< emacs-major-version 24) + ;; Emacs 23 doesn't have syntax-propertize-function + (set (make-local-variable 'font-lock-syntactic-keywords) + (list + `(,julia-char-regex + (1 "\"") ; Treat ' as a string delimiter. + (2 ".") ; Don't highlight anything between the open and close '. + (3 "\"")) ; Treat the close ' as a string delimiter. + `(,julia-triple-quoted-string-regex + (1 "\"") ; Treat the first " in """ as a string delimiter. + (2 ".") ; Don't highlight anything between. + (3 "\"")))) ; Treat the last " in """ as a string delimiter. + ;; Emacs 24 and later has syntax-propertize-function, so use that instead. + (set (make-local-variable 'syntax-propertize-function) + julia-syntax-propertize-function)) + (set (make-local-variable 'indent-line-function) 'julia-indent-line) + (set (make-local-variable 'beginning-of-defun-function) #'julia-beginning-of-defun) + (set (make-local-variable 'end-of-defun-function) #'julia-end-of-defun) + (setq indent-tabs-mode nil) + (setq imenu-generic-expression julia-imenu-generic-expression) + (imenu-add-to-menubar "Imenu")) + +(defun julia-manual-deindent () + "Deindent by `julia-indent-offset' regardless of current +indentation context. To be used to manually indent inside +strings." + (interactive) + (indent-line-to (max 0 (- (current-indentation) julia-indent-offset)))) +(define-key julia-mode-map (kbd "") 'julia-manual-deindent) + +(defvar julia-latexsubs (make-hash-table :test 'equal)) + +(defun julia-latexsub () + "Perform a LaTeX-like Unicode symbol substitution." + (interactive "*i") + (let ((orig-pt (point))) + (while (not (or (bobp) (= ?\\ (char-before)) + (= ?\s (char-syntax (char-before))))) + (backward-char)) + (if (and (not (bobp)) (= ?\\ (char-before))) + (progn + (backward-char) + (let ((sub (gethash (buffer-substring (point) orig-pt) julia-latexsubs))) + (if sub + (progn + (delete-region (point) orig-pt) + (insert sub)) + (goto-char orig-pt)))) + (goto-char orig-pt)))) + +(defalias 'latexsub 'julia-latexsub) + +(defun julia-latexsub-or-indent (arg) + "Either indent according to mode or perform a LaTeX-like symbol substution" + (interactive "*i") + (if (latexsub) + (indent-for-tab-command arg))) +(define-key julia-mode-map (kbd "TAB") 'julia-latexsub-or-indent) + +(defalias 'latexsub-or-indent 'julia-latexsub-or-indent) + +;;; populate LaTeX symbols hash table from a generated file. +;;; (See Julia issue #8947 for why we don't use the Emacs tex input mode.) +(load (expand-file-name "julia-latexsubs" (file-name-directory load-file-name))) + +;; Math insertion in julia. Use it with +;; (add-hook 'julia-mode-hook 'julia-math-mode) +;; (add-hook 'inferior-julia-mode-hook 'julia-math-mode) + +(when (require 'latex nil t) + (declare-function LaTeX-math-abbrev-prefix "latex") + + (defun julia-math-insert (s) + "Inserts math symbol given by `s'" + (when s + (let ((sym (gethash (concat "\\" s) julia-latexsubs))) + (when sym + (insert sym))))) + + (with-no-warnings + (define-minor-mode julia-math-mode + "A minor mode with easy access to TeX math commands. The +command is only entered if it is supported in Julia. The +following commands are defined: + +\\{LaTeX-math-mode-map}" + nil nil (list (cons (LaTeX-math-abbrev-prefix) LaTeX-math-keymap)) + (if julia-math-mode + (set (make-local-variable 'LaTeX-math-insert-function) + 'julia-math-insert))))) + +;; Code for `inferior-julia-mode' +(require 'comint) + +(defcustom julia-program "julia" + "Path to the program used by `inferior-julia'." + :type 'string + :group 'julia) + +(defcustom julia-arguments '("-i" "--color=yes") + "Commandline arguments to pass to `julia-program'." + :type '(repeat (string :tag "argument")) + :group 'julia) + +(defvar julia-prompt-regexp "^\\w*> " + "Regexp for matching `inferior-julia' prompt.") + +(defvar inferior-julia-mode-map + (let ((map (nconc (make-sparse-keymap) comint-mode-map))) + ;; example definition + (define-key map (kbd "TAB") 'julia-latexsub-or-indent) + map) + "Basic mode map for `inferior-julia-mode'.") + +;;;###autoload +(defun inferior-julia () + "Run an inferior instance of `julia' inside Emacs." + (interactive) + (let ((julia-program julia-program) + (buffer (get-buffer-create "*Julia*"))) + (when (not (comint-check-proc "*Julia*")) + (apply #'make-comint-in-buffer "Julia" "*Julia*" + julia-program nil julia-arguments)) + (pop-to-buffer-same-window "*Julia*") + (inferior-julia-mode))) + +(defun inferior-julia--initialize () + "Helper function to initialize `inferior-julia'." + (setq comint-use-prompt-regexp t)) + +(define-derived-mode inferior-julia-mode comint-mode "Julia" + "Major mode for `inferior-julia'. + +\\" + nil "Julia" + (setq comint-prompt-regexp julia-prompt-regexp) + (setq comint-prompt-read-only t) + (set (make-local-variable 'font-lock-defaults) '(julia-font-lock-keywords t)) + (set (make-local-variable 'paragraph-start) julia-prompt-regexp) + (set (make-local-variable 'indent-line-function) 'julia-indent-line)) + +(add-hook 'inferior-julia-mode-hook 'inferior-julia--initialize) + +;;;###autoload +(defalias 'run-julia #'inferior-julia + "Run an inferior instance of `julia' inside Emacs.") + +(provide 'julia-mode) + +;; Local Variables: +;; coding: utf-8 +;; byte-compile-warnings: (not obsolete) +;; End: +;;; julia-mode.el ends here diff --git a/elpa/julia-mode-readme.txt b/elpa/julia-mode-readme.txt new file mode 100644 index 00000000..19296213 --- /dev/null +++ b/elpa/julia-mode-readme.txt @@ -0,0 +1 @@ +This is the official Emacs mode for editing Julia programs. diff --git a/elpa/pcre2el-20161120.2103/pcre2el-autoloads.el b/elpa/pcre2el-20161120.2103/pcre2el-autoloads.el new file mode 100644 index 00000000..7d0e6568 --- /dev/null +++ b/elpa/pcre2el-20161120.2103/pcre2el-autoloads.el @@ -0,0 +1,217 @@ +;;; pcre2el-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "pcre2el" "pcre2el.el" (23997 31476 537680 +;;;;;; 409000)) +;;; Generated autoloads from pcre2el.el + +(defvar pcre-mode nil "\ +Non-nil if PCRE mode is enabled. +See the `pcre-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `pcre-mode'.") + +(custom-autoload 'pcre-mode "pcre2el" nil) + +(autoload 'pcre-mode "pcre2el" "\ +Use emulated PCRE syntax for regexps wherever possible. + +Advises the `interactive' specs of `read-regexp' and the +following other functions so that they read PCRE syntax and +translate to its Emacs equivalent: + +- `align-regexp' +- `find-tag-regexp' +- `sort-regexp-fields' +- `isearch-message-prefix' +- `ibuffer-do-replace-regexp' + +Also alters the behavior of `isearch-mode' when searching by regexp. + +\(fn &optional ARG)" t nil) + +(autoload 'pcre-query-replace-regexp "pcre2el" "\ +Perform `query-replace-regexp' using PCRE syntax. + +Consider using `pcre-mode' instead of this function. + +\(fn)" t nil) + +(autoload 'rxt-elisp-to-pcre "pcre2el" "\ +Translate REGEXP, a regexp in Emacs Lisp syntax, to Perl-compatible syntax. + +Interactively, reads the regexp in one of three ways. With a +prefix arg, reads from minibuffer without string escaping, like +`query-replace-regexp'. Without a prefix arg, uses the text of +the region if it is active. Otherwise, uses the result of +evaluating the sexp before point (which might be a string regexp +literal or an expression that produces a string). + +Displays the translated PCRE regexp in the echo area and copies +it to the kill ring. + +Emacs regexp features such as syntax classes which cannot be +translated to PCRE will cause an error. + +\(fn REGEXP)" t nil) + +(autoload 'rxt-elisp-to-rx "pcre2el" "\ +Translate REGEXP, a regexp in Emacs Lisp syntax, to `rx' syntax. + +See `rxt-elisp-to-pcre' for a description of the interactive +behavior and `rx' for documentation of the S-expression based +regexp syntax. + +\(fn REGEXP)" t nil) + +(autoload 'rxt-elisp-to-strings "pcre2el" "\ +Return a list of all strings matched by REGEXP, an Emacs Lisp regexp. + +See `rxt-elisp-to-pcre' for a description of the interactive behavior. + +This is useful primarily for getting back the original list of +strings from a regexp generated by `regexp-opt', but it will work +with any regexp without unbounded quantifiers (*, +, {2, } and so +on). + +Throws an error if REGEXP contains any infinite quantifiers. + +\(fn REGEXP)" t nil) + +(autoload 'rxt-toggle-elisp-rx "pcre2el" "\ +Toggle the regexp near point between Elisp string and rx syntax. + +\(fn)" t nil) + +(autoload 'rxt-pcre-to-elisp "pcre2el" "\ +Translate PCRE, a regexp in Perl-compatible syntax, to Emacs Lisp. + +Interactively, uses the contents of the region if it is active, +otherwise reads from the minibuffer. Prints the Emacs translation +in the echo area and copies it to the kill ring. + +PCRE regexp features that cannot be translated into Emacs syntax +will cause an error. See the commentary section of pcre2el.el for +more details. + +\(fn PCRE &optional FLAGS)" t nil) + +(defalias 'pcre-to-elisp 'rxt-pcre-to-elisp) + +(autoload 'rxt-pcre-to-rx "pcre2el" "\ +Translate PCRE, a regexp in Perl-compatible syntax, to `rx' syntax. + +See `rxt-pcre-to-elisp' for a description of the interactive behavior. + +\(fn PCRE &optional FLAGS)" t nil) + +(autoload 'rxt-pcre-to-strings "pcre2el" "\ +Return a list of all strings matched by PCRE, a Perl-compatible regexp. + +See `rxt-elisp-to-pcre' for a description of the interactive +behavior and `rxt-elisp-to-strings' for why this might be useful. + +Throws an error if PCRE contains any infinite quantifiers. + +\(fn PCRE &optional FLAGS)" t nil) + +(autoload 'rxt-explain-elisp "pcre2el" "\ +Insert the pretty-printed `rx' syntax for REGEXP in a new buffer. + +REGEXP is a regular expression in Emacs Lisp syntax. See +`rxt-elisp-to-pcre' for a description of how REGEXP is read +interactively. + +\(fn REGEXP)" t nil) + +(autoload 'rxt-explain-pcre "pcre2el" "\ +Insert the pretty-printed `rx' syntax for REGEXP in a new buffer. + +REGEXP is a regular expression in PCRE syntax. See +`rxt-pcre-to-elisp' for a description of how REGEXP is read +interactively. + +\(fn REGEXP &optional FLAGS)" t nil) + +(autoload 'rxt-quote-pcre "pcre2el" "\ +Return a PCRE regexp which matches TEXT literally. + +Any PCRE metacharacters in TEXT will be quoted with a backslash. + +\(fn TEXT)" nil nil) + +(autoload 'rxt-explain "pcre2el" "\ +Pop up a buffer with pretty-printed `rx' syntax for the regex at point. + +Chooses regex syntax to read based on current major mode, calling +`rxt-explain-elisp' if buffer is in `emacs-lisp-mode' or +`lisp-interaction-mode', or `rxt-explain-pcre' otherwise. + +\(fn)" t nil) + +(autoload 'rxt-convert-syntax "pcre2el" "\ +Convert regex at point to other kind of syntax, depending on major mode. + +For buffers in `emacs-lisp-mode' or `lisp-interaction-mode', +calls `rxt-elisp-to-pcre' to convert to PCRE syntax. Otherwise, +calls `rxt-pcre-to-elisp' to convert to Emacs syntax. + +The converted syntax is displayed in the echo area and copied to +the kill ring; see the two functions named above for details. + +\(fn)" t nil) + +(autoload 'rxt-convert-to-rx "pcre2el" "\ +Convert regex at point to RX syntax. Chooses Emacs or PCRE syntax by major mode. + +\(fn)" t nil) + +(autoload 'rxt-convert-to-strings "pcre2el" "\ +Convert regex at point to RX syntax. Chooses Emacs or PCRE syntax by major mode. + +\(fn)" t nil) + +(autoload 'rxt-mode "pcre2el" "\ +Regex translation utilities. + +\(fn &optional ARG)" t nil) + +(autoload 'turn-on-rxt-mode "pcre2el" "\ +Turn on `rxt-mode' in the current buffer. + +\(fn)" t nil) + +(defvar rxt-global-mode nil "\ +Non-nil if Rxt-Global mode is enabled. +See the `rxt-global-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `rxt-global-mode'.") + +(custom-autoload 'rxt-global-mode "pcre2el" nil) + +(autoload 'rxt-global-mode "pcre2el" "\ +Toggle Rxt mode in all buffers. +With prefix ARG, enable Rxt-Global mode if ARG is positive; +otherwise, disable it. If called from Lisp, enable the mode if +ARG is omitted or nil. + +Rxt mode is enabled in all buffers where +`turn-on-rxt-mode' would do it. +See `rxt-mode' for more information on Rxt mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; pcre2el-autoloads.el ends here diff --git a/elpa/pcre2el-20161120.2103/pcre2el-pkg.el b/elpa/pcre2el-20161120.2103/pcre2el-pkg.el new file mode 100644 index 00000000..e0297eb8 --- /dev/null +++ b/elpa/pcre2el-20161120.2103/pcre2el-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "pcre2el" "20161120.2103" "regexp syntax converter" '((emacs "24") (cl-lib "0.3")) :commit "0b5b2a2c173aab3fd14aac6cf5e90ad3bf58fa7d" :authors '(("joddie ")) :maintainer '("joddie ") :url "https://github.com/joddie/pcre2el") diff --git a/elpa/pcre2el-20161120.2103/pcre2el.el b/elpa/pcre2el-20161120.2103/pcre2el.el new file mode 100644 index 00000000..bea8effe --- /dev/null +++ b/elpa/pcre2el-20161120.2103/pcre2el.el @@ -0,0 +1,3157 @@ +;;; pcre2el.el --- regexp syntax converter -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2015 Jon Oddie + +;; Author: joddie +;; Hacked additionally by: opensource at hardakers dot net +;; Created: 14 Feb 2012 +;; Updated: 13 December 2015 +;; Version: 1.8 +;; Package-Version: 20161120.2103 +;; Url: https://github.com/joddie/pcre2el +;; Package-Requires: ((emacs "24") (cl-lib "0.3")) + +;; This file is NOT part of GNU Emacs. + +;; This program 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. +;; +;; This program 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 this program. If not, see `http://www.gnu.org/licenses/'. + +;; This file incorporates work covered by the following copyright and +;; permission notice: +;; +;; Copyright (c) 1993-2002 Richard Kelsey and Jonathan Rees +;; Copyright (c) 1994-2002 by Olin Shivers and Brian D. Carlstrom. +;; Copyright (c) 1999-2002 by Martin Gasbichler. +;; Copyright (c) 2001-2002 by Michael Sperber. +;; All rights reserved. +;; +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following conditions +;; are met: 1. Redistributions of source code must retain the above +;; copyright notice, this list of conditions and the following +;; disclaimer. 2. Redistributions in binary form must reproduce the +;; above copyright notice, this list of conditions and the following +;; disclaimer in the documentation and/or other materials provided +;; with the distribution. 3. The name of the authors may not be used +;; to endorse or promote products derived from this software without +;; specific prior written permission. +;; +;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR +;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY +;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +;;; Commentary: + +;; 1 Overview +;; ========== + +;; `pcre2el' or `rxt' (RegeXp Translator or RegeXp Tools) is a utility +;; for working with regular expressions in Emacs, based on a +;; recursive-descent parser for regexp syntax. In addition to converting +;; (a subset of) PCRE syntax into its Emacs equivalent, it can do the +;; following: + +;; - convert Emacs syntax to PCRE +;; - convert either syntax to `rx', an S-expression based regexp syntax +;; - untangle complex regexps by showing the parse tree in `rx' form and +;; highlighting the corresponding chunks of code +;; - show the complete list of strings (productions) matching a regexp, +;; provided the list is finite +;; - provide live font-locking of regexp syntax (so far only for Elisp +;; buffers -- other modes on the TODO list) + + +;; 2 Usage +;; ======= + +;; Enable `rxt-mode' or its global equivalent `rxt-global-mode' to get +;; the default key-bindings. There are three sets of commands: commands +;; that take a PCRE regexp, commands which take an Emacs regexp, and +;; commands that try to do the right thing based on the current +;; mode. Currently, this means Emacs syntax in `emacs-lisp-mode' and +;; `lisp-interaction-mode', and PCRE syntax everywhere else. + +;; The default key bindings all begin with `C-c /' and have a mnemonic +;; structure: `C-c / ', or just `C-c / ' for the +;; "do what I mean" commands. The complete list of key bindings is given +;; here and explained in more detail below: + +;; - "Do-what-I-mean" commands: +;; `C-c / /': `rxt-explain' +;; `C-c / c': `rxt-convert-syntax' +;; `C-c / x': `rxt-convert-to-rx' +;; `C-c / '': `rxt-convert-to-strings' + +;; - Commands that work on a PCRE regexp: +;; `C-c / p e': `rxt-pcre-to-elisp' +;; `C-c / %': `pcre-query-replace-regexp' +;; `C-c / p x': `rxt-pcre-to-rx' +;; `C-c / p '': `rxt-pcre-to-strings' +;; `C-c / p /': `rxt-explain-pcre' + +;; - Commands that work on an Emacs regexp: +;; `C-c / e /': `rxt-explain-elisp' +;; `C-c / e p': `rxt-elisp-to-pcre' +;; `C-c / e x': `rxt-elisp-to-rx' +;; `C-c / e '': `rxt-elisp-to-strings' +;; `C-c / e t': `rxt-toggle-elisp-rx' +;; `C-c / t': `rxt-toggle-elisp-rx' + + +;; 2.1 Interactive input and output +;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +;; When used interactively, the conversion commands can read a regexp +;; either from the current buffer or from the minibuffer. The output is +;; displayed in the minibuffer and copied to the kill-ring. + +;; - When called with a prefix argument (`C-u'), they read a regular +;; expression from the minibuffer literally, without further processing +;; -- meaning there's no need to double the backslashes if it's an +;; Emacs regexp. This is the same way commands like +;; `query-replace-regexp' read input. + +;; - When the region is active, they use they the region contents, again +;; literally (without any translation of string syntax). + +;; - With neither a prefix arg nor an active region, the behavior depends +;; on whether the command expects an Emacs regexp or a PCRE one. + +;; Commands that take an Emacs regexp behave like `C-x C-e': they +;; evaluate the sexp before point (which could be simply a string +;; literal) and use its value. This is designed for use in Elisp +;; buffers. As a special case, if point is *inside* a string, it's +;; first moved to the string end, so in practice they should work as +;; long as point is somewhere within the regexp literal. + +;; Commands that take a PCRE regexp try to read a Perl-style delimited +;; regex literal *after* point in the current buffer, including its +;; flags. For example, putting point before the `m' in the following +;; example and doing `C-c / p e' (`rxt-pcre-to-elisp') displays +;; `\(?:bar\|foo\)', correctly stripping out the whitespace and +;; comment: + +;; ,---- +;; | $x =~ m/ foo | (?# comment) bar /x +;; `---- + +;; The PCRE reader currently only works with `/ ... /' delimiters. It +;; will ignore any preceding `m', `s', or `qr' operator, as well as the +;; replacement part of an `s' construction. + +;; Readers for other PCRE-using languages are on the TODO list. + +;; The translation functions display their result in the minibuffer and +;; copy it to the kill ring. When translating something into Elisp +;; syntax, you might need to use the result either literally (e.g. for +;; interactive input to a command like `query-replace-regexp'), or as a +;; string to paste into Lisp code. To allow both uses, +;; `rxt-pcre-to-elisp' copies both versions successively to the +;; kill-ring. The literal regexp without string quoting is the top +;; element of the kill-ring, while the Lisp string is the +;; second-from-top. You can paste the literal regexp somewhere by doing +;; `C-y', or the Lisp string by `C-y M-y'. + + +;; 2.2 Syntax conversion commands +;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +;; `rxt-convert-syntax' (`C-c / c') converts between Emacs and PCRE +;; syntax, depending on the major mode in effect when called. +;; Alternatively, you can specify the conversion direction explicitly by +;; using either `rxt-pcre-to-elisp' (`C-c / p e') or `rxt-elisp-to-pcre' +;; (`C-c / e p'). + +;; Similarly, `rxt-convert-to-rx' (`C-c / x') converts either kind of +;; syntax to `rx' form, while `rxt-convert-pcre-to-rx' (`C-c / p x') and +;; `rxt-convert-elisp-to-rx' (`C-c / e x') convert to `rx' from a +;; specified source type. + +;; In Elisp buffers, you can use `rxt-toggle-elisp-rx' (`C-c / t' or `C-c +;; / e t') to switch the regexp at point back and forth between string +;; and `rx' syntax. Point should either be within an `rx' or +;; `rx-to-string' form or a string literal for this to work. + + +;; 2.3 PCRE mode (experimental) +;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +;; If you want to use emulated PCRE regexp syntax in all Emacs commands, +;; try `pcre-mode', which uses Emacs's advice system to make all commands +;; that read regexps using the minibuffer use emulated PCRE syntax. It +;; should also work with Isearch. + +;; This feature is still fairly experimental. It may fail to work or do +;; the wrong thing with certain commands. Please report bugs. + +;; `pcre-query-replace-regexp' was originally defined to do query-replace +;; using emulated PCRE regexps, and is now made somewhat obsolete by +;; `pcre-mode'. It is bound to `C-c / %' by default, by analogy with +;; `M-%'. Put the following in your `.emacs' if you want to use +;; PCRE-style query replacement everywhere: + +;; ,---- +;; | (global-set-key [(meta %)] 'pcre-query-replace-regexp) +;; `---- + +;; 2.5 Explain regexps +;; ~~~~~~~~~~~~~~~~~~~ + +;; When syntax-highlighting isn't enough to untangle some gnarly regexp +;; you find in the wild, try the 'explain' commands: `rxt-explain' (`C-c +;; / /'), `rxt-explain-pcre' (`C-c / p') and `rxt-explain-elisp' (`C-c / +;; e'). These display the original regexp along with its pretty-printed +;; `rx' equivalent in a new buffer. Moving point around either in the +;; original regexp or the `rx' translation highlights corresponding +;; pieces of syntax, which can aid in seeing things like the scope of +;; quantifiers. + +;; I call them "explain" commands because the `rx' form is close to a +;; plain syntax tree, and this plus the wordiness of the operators +;; usually helps to clarify what is going on. People who dislike Lisp +;; syntax might disagree with this assessment. + + +;; 2.6 Generate all matching strings (productions) +;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +;; Occasionally you come across a regexp which is designed to match a +;; finite set of strings, e.g. a set of keywords, and it would be useful +;; to recover the original set. (In Emacs you can generate such regexps +;; using `regexp-opt'). The commands `rxt-convert-to-strings' (`C-c / +;; ′'), `rxt-pcre-to-strings' (`C-c / p ′') or `rxt-elisp-to-strings' +;; (`C-c / e ′') accomplish this by generating all the matching strings +;; ("productions") of a regexp. (The productions are copied to the kill +;; ring as a Lisp list). + +;; An example in Lisp code: + +;; ,---- +;; | (regexp-opt '("cat" "caterpillar" "catatonic")) +;; | ;; => "\\(?:cat\\(?:atonic\\|erpillar\\)?\\)" +;; | (rxt-elisp-to-strings "\\(?:cat\\(?:atonic\\|erpillar\\)?\\)") +;; | ;; => '("cat" "caterpillar" "catatonic") +;; `---- + +;; For obvious reasons, these commands only work with regexps that don't +;; include any unbounded quantifiers like `+' or `*'. They also can't +;; enumerate all the characters that match a named character class like +;; `[[:alnum:]]'. In either case they will give a (hopefully meaningful) +;; error message. Due to the nature of permutations, it's still possible +;; for a finite regexp to generate a huge number of productions, which +;; will eat memory and slow down your Emacs. Be ready with `C-g' if +;; necessary. + + +;; 2.7 RE-Builder support +;; ~~~~~~~~~~~~~~~~~~~~~~ + +;; The Emacs RE-Builder is a useful visual tool which allows using +;; several different built-in syntaxes via `reb-change-syntax' (`C-c +;; TAB'). It supports Elisp read and literal syntax and `rx', but it can +;; only convert from the symbolic forms to Elisp, not the other way. This +;; package hacks the RE-Builder to also work with emulated PCRE syntax, +;; and to convert transparently between Elisp, PCRE and rx syntaxes. PCRE +;; mode reads a delimited Perl-like literal of the form `/ ... /', and it +;; should correctly support using the `x' and `s' flags. + + +;; 2.8 Use from Lisp +;; ~~~~~~~~~~~~~~~~~ + +;; Example of using the conversion functions: +;; ,---- +;; | (rxt-pcre-to-elisp "(abc|def)\\w+\\d+") +;; | ;; => "\\(\\(?:abc\\|def\\)\\)[_[:alnum:]]+[[:digit:]]+" +;; `---- + +;; All the conversion functions take a single string argument, the regexp +;; to translate: + +;; - `rxt-pcre-to-elisp' +;; - `rxt-pcre-to-rx' +;; - `rxt-pcre-to-strings' +;; - `rxt-elisp-to-pcre' +;; - `rxt-elisp-to-rx' +;; - `rxt-elisp-to-strings' + + +;; 3 Bugs and Limitations +;; ====================== + +;; 3.1 Limitations on PCRE syntax +;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +;; PCRE has a complicated syntax and semantics, only some of which can be +;; translated into Elisp. The following subset of PCRE should be +;; correctly parsed and converted: + +;; - parenthesis grouping `( .. )', including shy matches `(?: ... )' +;; - backreferences (various syntaxes), but only up to 9 per expression +;; - alternation `|' +;; - greedy and non-greedy quantifiers `*', `*?', `+', `+?', `?' and `??' +;; (all of which are the same in Elisp as in PCRE) +;; - numerical quantifiers `{M,N}' +;; - beginning/end of string `\A', `\Z' +;; - string quoting `\Q .. \E' +;; - word boundaries `\b', `\B' (these are the same in Elisp) +;; - single character escapes `\a', `\c', `\e', `\f', `\n', `\r', `\t', +;; `\x', and `\octal digits' (but see below about non-ASCII characters) +;; - character classes `[...]' including Posix escapes +;; - character classes `\d', `\D', `\h', `\H', `\s', `\S', `\v', `\V' +;; both within character class brackets and outside +;; - word and non-word characters `\w' and `\W' (Emacs has the same +;; syntax, but its meaning is different) +;; - `s' (single line) and `x' (extended syntax) flags, in regexp +;; literals, or set within the expression via `(?xs-xs)' or `(?xs-xs: +;; .... )' syntax +;; - comments `(?# ... )' + +;; Most of the more esoteric PCRE features can't really be supported by +;; simple translation to Elisp regexps. These include the different +;; lookaround assertions, conditionals, and the "backtracking control +;; verbs" `(* ...)' . OTOH, there are a few other syntaxes which are +;; currently unsupported and possibly could be: + +;; - `\L', `\U', `\l', `\u' case modifiers +;; - `\g{...}' backreferences + + +;; 3.2 Other limitations +;; ~~~~~~~~~~~~~~~~~~~~~ + +;; - The order of alternatives and characters in char classes sometimes +;; gets shifted around, which is annoying. +;; - Although the string parser tries to interpret PCRE's octal and +;; hexadecimal escapes correctly, there are problems with matching +;; 8-bit characters that I don't use enough to properly understand, +;; e.g.: +;; ,---- +;; | (string-match-p (rxt-pcre-to-elisp "\\377") "\377") => nil +;; `---- +;; A fix for this would be welcome. + +;; - Most of PCRE's rules for how `^', `\A', `$' and `\Z' interact with +;; newlines are not implemented, since they seem less relevant to +;; Emacs's buffer-oriented rather than line-oriented model. However, +;; the different meanings of the `.' metacharacter *are* implemented +;; (it matches newlines with the `/s' flag, but not otherwise). + +;; - Not currently namespace clean (both `rxt-' and a couple of `pcre-' +;; functions). + + +;; 3.3 TODO: +;; ~~~~~~~~~ + +;; - Python-specific extensions to PCRE? +;; - Language-specific stuff to enable regexp font-locking and explaining +;; in different modes. Each language would need two functions, which +;; could be kept in an alist: + +;; 1. A function to read PCRE regexps, taking the string syntax into +;; account. E.g., Python has single-quoted, double-quoted and raw +;; strings, each with different quoting rules. PHP has the kind of +;; belt-and-suspenders solution you would expect: regexps are in +;; strings, /and/ you have to include the `/ ... /' delimiters! +;; Duh. + +;; 2. A function to copy faces back from the parsed string to the +;; original buffer text. This has to recognize any escape sequences +;; so they can be treated as a single character. + + +;; 4 Internal details +;; ================== + +;; `rxt' defines an internal syntax tree representation of regular +;; expressions, parsers for Elisp and PCRE syntax, and 'unparsers' +;; to convert the internal representation to PCRE or `rx' syntax. +;; Converting from the internal representation to Emacs syntax is +;; done by converting to `rx' form and passing it to `rx-to-string'. +;; See `rxt-parse-re', `rxt-adt->pcre', and `rxt-adt->rx' for +;; details. + +;; This code is partially based on Olin Shivers' reference SRE +;; implementation in scsh, although it is simplified in some respects and +;; extended in others. See `scsh/re.scm', `scsh/spencer.scm' and +;; `scsh/posixstr.scm' in the `scsh' source tree for details. In +;; particular, `pcre2el' steals the idea of an abstract data type for +;; regular expressions and the general structure of the string regexp +;; parser and unparser. The data types for character sets are extended in +;; order to support symbolic translation between character set +;; expressions without assuming a small (Latin1) character set. The +;; string parser is also extended to parse a bigger variety of +;; constructions, including POSIX character classes and various Emacs and +;; Perl regexp assertions. Otherwise, only the bare minimum of scsh's +;; abstract data type is implemented. + + +;; 5 Soapbox +;; ========= + +;; Emacs regexps have their annoyances, but it is worth getting used to +;; them. The Emacs assertions for word boundaries, symbol boundaries, and +;; syntax classes depending on the syntax of the mode in effect are +;; especially useful. (PCRE has `\b' for word-boundary, but AFAIK it +;; doesn't have separate assertions for beginning-of-word and +;; end-of-word). Other things that might be done with huge regexps in +;; other languages can be expressed more understandably in Elisp using +;; combinations of `save-excursion' with the various searches (regexp, +;; literal, skip-syntax-forward, sexp-movement functions, etc.). + +;; There's not much point in using `rxt-pcre-to-elisp' to use PCRE +;; notation in a Lisp program you're going to maintain, since you still +;; have to double all the backslashes. Better to just use the converted +;; result (or better yet, the `rx' form). + + +;; 6 History and acknowledgments +;; ============================= + +;; This was originally created out of an answer to a stackoverflow +;; question: +;; [http://stackoverflow.com/questions/9118183/elisp-mechanism-for-converting-pcre-regexps-to-emacs-regexps] + +;; Thanks to: + +;; - Wes Hardaker (hardaker) for the initial inspiration and subsequent +;; hacking +;; - priyadarshan for requesting RX support +;; - Daniel Colascione (dcolascione) for a patch to support Emacs's +;; explicitly-numbered match groups +;; - Aaron Meurer (asmeurer) for requesting Isearch support +;; - Philippe Vaucher (silex) for a patch to support `ibuffer-do-replace-regexp' +;; in PCRE mode + +;;; Code: + +(require 'cl-lib) +(require 'rx) +(require 're-builder) +(require 'advice) +(require 'ring) +(require 'pcase) + +;;; Customization group +(defgroup rxt nil + "Regex syntax converter and utilities." + :version 1.2 + :group 'tools + :group 'lisp + :link '(emacs-commentary-link :tag "commentary" "pcre2el.el") + :link '(emacs-library-link :tag "lisp file" "pcre2el.el") + :link '(url-link :tag "web page" "https://github.com/joddie/pcre2el")) + +(defface rxt-highlight-face + '((((min-colors 16581375) (background light)) :background "#eee8d5") + (((min-colors 16581375) (background dark)) :background "#222222")) + "Face for highlighting corresponding regex syntax in `rxt-explain' buffers." + :group 'rxt) + +(defcustom rxt-verbose-rx-translation nil + "Non-nil if `rxt-pcre-to-rx' and `rxt-elisp-to-rx' should use verbose `rx' primitives. + +Verbose primitives are things like `line-start' instead of `bol', +etc." + :group 'rxt + :type 'boolean) + +(defcustom rxt-explain-verbosely t + "Non-nil if `rxt-explain-elisp' and `rxt-explain-pcre' should use verbose `rx' primitives. + +This overrides the value of `rxt-verbose-rx-translation' for +these commands only." + :group 'rxt + :type 'boolean) + + +;;;; Macros and functions for writing interactive input and output + +;; Macros for handling return values. If called interactively, +;; display the value in the echo area and copy it to the kill ring, +;; otherwise just return the value. PCREs are copied as unquoted +;; strings for yanking into Perl, JS, etc. `rx' forms and other sexps +;; are copied as `read'-able literals for yanking into Elisp buffers. +;; Emacs regexps are copied twice: once as an unquoted value for +;; interactive use, and once as a readable string literal for yanking +;; into Elisp buffers. +(defmacro rxt-return-pcre (expr) + (let ((value (make-symbol "value"))) + `(let ((,value ,expr)) + (when (called-interactively-p 'any) + (rxt--kill-pcre ,value)) + ,value))) + +(defmacro rxt-return-sexp (expr) + (let ((value (make-symbol "value"))) + `(let ((,value ,expr)) + (when (called-interactively-p 'any) + (rxt--kill-sexp ,value)) + ,value))) + +(defmacro rxt-return-emacs-regexp (expr) + (let ((value (make-symbol "value"))) + `(let ((,value ,expr)) + (when (called-interactively-p 'any) + (rxt--kill-emacs-regexp ,value)) + ,value))) + +(defun rxt--kill-sexp (value) + (let ((lisp-literal (prin1-to-string value))) + (message "%s" lisp-literal) + (kill-new lisp-literal))) + +(defun rxt--kill-pcre (value) + (message "%s" value) + (kill-new value)) + +(defun rxt--kill-emacs-regexp (value) + (let ((lisp-literal (prin1-to-string value))) + (message "%s" value) + (kill-new lisp-literal) + (kill-new value))) + +;; Read an Elisp regexp interactively. +;; +;; Three possibilities: +;; +;; 1) With a prefix arg, reads literally from the minibuffer, w/o +;; using string syntax -- just like query-replace-regexp, etc. +;; +;; 2) If the region is active, use the text of the region literally +;; (again w/o string syntax) +;; +;; 3) Otherwise, eval the sexp before point (which might be a string +;; literal or an expression) and use its value. Falls back to method +;; (1) if this fails to produce a string value. +;; +(cl-defun rxt-interactive/elisp (&optional (prompt "Emacs regexp: ")) + (list + (cond (current-prefix-arg + (read-string prompt)) + + ((use-region-p) + (buffer-substring-no-properties (region-beginning) (region-end))) + + (t + (condition-case nil + (save-excursion + (while (nth 3 (syntax-ppss)) (forward-char)) + (let ((re (eval (preceding-sexp)))) + (if (stringp re) re + (read-string prompt)))) + (error + (read-string prompt))))))) + +;; Read a PCRE regexp interactively. +;; +;; Three possibilities: As above, except that without prefix arg or +;; active region, tries to read a delimited regexp literal like /.../, +;; m/.../, or qr/.../ following point in the current buffer. Falls +;; back to reading from minibuffer if that fails. +;; +;; Returns the regexp, with flags as text properties. +;; +;; TODO: Different delimiters +(cl-defun rxt-interactive/pcre (&optional (prompt "PCRE regexp: ")) + (list + (cond (current-prefix-arg + (rxt--read-pcre prompt)) + + ((use-region-p) + (buffer-substring-no-properties (region-beginning) (region-end))) + + (t + (condition-case nil + (rxt-read-delimited-pcre) + (error ; Fall back to reading from minibuffer + (rxt--read-pcre prompt))))) + nil)) + +(define-minor-mode rxt--read-pcre-mode + "Minor-mode with key-bindings for toggling PCRE flags. + +You should not normally call this directly. It will be enabled +in minibuffers for `read-regexp' and in the `re-builder' buffer +when `pcre-mode' is active. These bindings will also be added to +`isearch-mode-map' in `pcre-mode'." + :initial nil + :lighter nil + :keymap + `((,(kbd "C-c s") . ,#'rxt--toggle-s-mode) + (,(kbd "C-c x") . ,#'rxt--toggle-x-mode) + (,(kbd "C-c i") . ,#'rxt--toggle-i-mode))) + +(defun rxt--read-pcre (prompt) + "Read a PCRE regexp for translation, together with option flags. + +The `s', `x', and `i' flags can be toggled using the following +commands: \\ + +\\[rxt--toggle-s-mode] : toggle `s' (single-line) mode +\\[rxt--toggle-x-mode] : toggle `x' (extended) mode +\\[rxt--toggle-i-mode] : toggle `i' (case-insensitive) mode + +In single-line mode, `.' will also match newlines. +In extended mode, whitespace is ignored. + +Case-insensitive mode emulates matching without case, +independently of Emacs's builtin `case-fold-search' setting. +Note that this does not apply to backreferences." + (minibuffer-with-setup-hook #'rxt--read-pcre-mode + (read-from-minibuffer prompt))) + +(defun rxt--toggle-s-mode () + "Toggle emulated PCRE single-line (s) flag." + (interactive) + (rxt--toggle-flag ?s)) + +(defun rxt--toggle-x-mode () + "Toggle emulated PCRE extended (x) flag." + (interactive) + (rxt--toggle-flag ?x)) + +(defun rxt--toggle-i-mode () + "Toggle emulated PCRE case-insensitive (i) flag." + (interactive) + (rxt--toggle-flag ?i)) + +(defun rxt--toggle-flag (char) + "Toggle CHAR, a PCRE flag." + (cond + ((derived-mode-p 'reb-mode) ; RE-Builder + (rxt--toggle-flag-re-builder char)) + ((minibufferp) + (rxt--toggle-flag-minibuffer char)) + (isearch-mode + (rxt--toggle-flag-isearch char)) + (t + (error "Not in minibuffer, RE-Builder or isearch mode.")))) + +(defun rxt--toggle-flag-re-builder (char) + (save-excursion + (goto-char (point-max)) + (search-backward "/") + (forward-char) + (when (looking-at (rx (* (any ?i ?s ?x)))) + (let ((inhibit-modification-hooks t)) + (replace-match (rxt--xor-flags (match-string 0) char) t t)))) + (reb-do-update)) + +(defun rxt--toggle-flag-minibuffer (char) + (setf (buffer-substring (minibuffer-prompt-end) (point-max)) + (rxt--toggle-flag-string (minibuffer-contents) char)) + (when + (and (= (point) (minibuffer-prompt-end)) + (looking-at (rx "(?" (group (+ (any ?i ?s ?x))) ")"))) + (forward-sexp))) + +(defun rxt--toggle-flag-isearch (char) + (when isearch-regexp + (setq isearch-string + (rxt--toggle-flag-string isearch-string char)) + (setq isearch-message + (mapconcat #'isearch-text-char-description isearch-string "")) + (isearch-search-and-update))) + +(defun rxt--toggle-flag-string (string char) + (if (string-match (rx string-start "(?" (group (+ (any ?i ?s ?x))) ")") + string) + (let ((flags (rxt--xor-flags (match-string 1 string) char))) + (if (string= flags "") + (replace-match "" t t string) + (replace-match flags t t string 1))) + (format "(?%c)%s" char string))) + +(defun rxt--xor-flags (flags char) + (concat + (sort + (cl-set-exclusive-or (string-to-list flags) (list char)) + #'<))) + + +;;;; Minor mode for using emulated PCRE syntax + +(defvar pcre-old-isearch-search-fun-function nil + "Original value of `isearch-search-fun-function' before entering `pcre-mode.' + +This function is wrapped by `pcre-isearch-search-fun-function' +and restored on exit from `pcre-mode'.") +(make-variable-buffer-local 'pcre-old-isearch-search-fun-function) + +(defvar pcre-old-isearch-key-bindings nil + "Alist of key-bindings to restore in `isearch-mode-map' on exiting `pcre-mode'.") + +;;;###autoload +(define-minor-mode pcre-mode + "Use emulated PCRE syntax for regexps wherever possible. + +Advises the `interactive' specs of `read-regexp' and the +following other functions so that they read PCRE syntax and +translate to its Emacs equivalent: + +- `align-regexp' +- `find-tag-regexp' +- `sort-regexp-fields' +- `isearch-message-prefix' +- `ibuffer-do-replace-regexp' + +Also alters the behavior of `isearch-mode' when searching by regexp." + nil " PCRE" + nil + :global t + + (if pcre-mode + ;; Enabling + (progn + ;; Enable advice + (ad-enable-regexp "pcre-mode") + ;; Set up isearch hooks + (add-hook 'isearch-mode-hook #'pcre-isearch-mode-hook) + (add-hook 'isearch-mode-end-hook #'pcre-isearch-mode-end-hook) + ;; Add the keybindings of `rxt--read-pcre-mode-map' to + ;; `isearch-mode-map' (so that they do not cause an exit from + ;; `isearch-mode'), and save any existing bindings for those + ;; keys to restore on exit from `pcre-mode'. + (setq pcre-old-isearch-key-bindings + (cl-loop for key being the key-seqs of rxt--read-pcre-mode-map + for def = (lookup-key isearch-mode-map key) + collect (cons (copy-sequence key) + (if (numberp def) nil def)))) + (cl-loop for key being the key-seqs of rxt--read-pcre-mode-map + using (key-bindings def) + do (define-key isearch-mode-map key def))) + + ;; Disable advice + (ad-disable-regexp "pcre-mode") + ;; Remove from isearch hooks + (remove-hook 'isearch-mode-hook #'pcre-isearch-mode-hook) + (remove-hook 'isearch-mode-end-hook #'pcre-isearch-mode-end-hook) + ;; Restore key-bindings + (cl-loop for (key . def) in pcre-old-isearch-key-bindings + do (define-key isearch-mode-map key def))) + + ;; "Activating" advice re-computes the function definitions, which + ;; is necessary whether enabling or disabling + (ad-activate-regexp "pcre-mode")) + +;;; Cache of PCRE -> Elisp translations +(defvar pcre-mode-cache-size 100 + "Number of PCRE-to-Emacs translations to keep in the `pcre-mode' cache.") + +(defvar pcre-mode-cache (make-hash-table :test 'equal) + "Cache of PCRE-to-Emacs translations used in `pcre-mode'. + +Keys are PCRE regexps, values are their Emacs equivalents.") + +(defvar pcre-mode-reverse-cache (make-hash-table :test 'equal) + "Cache of original PCREs translated to Emacs syntax in `pcre-mode'. + +Keys are translated Emacs regexps, values are their original PCRE +form. This is used to display the original PCRE regexp in place +of its translated form.") + +(defvar pcre-cache-ring (make-ring pcre-mode-cache-size) + "Ring of PCRE-to-Emacs translations used in `pcre-mode'. + +When the ring fills up, the oldest element is removed and the +corresponding entries are deleted from the hash tables +`pcre-mode-cache' and `pcre-mode-reverse-cache'.") + +(defun pcre-to-elisp/cached (pcre) + "Translate PCRE to Emacs syntax, caching both forms." + (or (gethash pcre pcre-mode-cache) + (let ((elisp (rxt-pcre-to-elisp pcre))) + (pcre-set-cache pcre elisp) + elisp))) + +(defun pcre-set-cache (pcre-regexp emacs-regexp) + "Add a PCRE-to-Emacs translation to the `pcre-mode' cache." + (when (and (not (zerop (length pcre-regexp))) + (not (zerop (length emacs-regexp))) + (not (gethash pcre-regexp pcre-mode-cache))) + (if (= (ring-length pcre-cache-ring) (ring-size pcre-cache-ring)) + (let* ((old-item (ring-remove pcre-cache-ring)) + (old-pcre (car old-item)) + (old-emacs (cdr old-item))) + (remhash old-pcre pcre-mode-cache) + (remhash old-emacs pcre-mode-reverse-cache)) + (puthash pcre-regexp emacs-regexp pcre-mode-cache) + (puthash emacs-regexp pcre-regexp pcre-mode-reverse-cache) + (ring-insert pcre-cache-ring (cons pcre-regexp emacs-regexp))))) + +;;; Isearch advice +(defun pcre-isearch-mode-hook () + (when (not (eq isearch-search-fun-function #'isearch-search-fun-default)) + (message "Warning: pcre-mode overriding existing isearch function `%s'" + isearch-search-fun-function)) + ;; Prevent an infinite loop, if a previous isearch in pcre-mode + ;; exited without restoring the original search function for some + ;; reason + (unless (eq isearch-search-fun-function #'pcre-isearch-search-fun-function) + (setq pcre-old-isearch-search-fun-function isearch-search-fun-function)) + (set (make-local-variable 'isearch-search-fun-function) + #'pcre-isearch-search-fun-function)) + +(defun pcre-isearch-mode-end-hook () + (setq isearch-search-fun-function pcre-old-isearch-search-fun-function)) + +(defun pcre-isearch-search-fun-function () + "Enable isearching using emulated PCRE syntax. + +This is set as the value of `isearch-search-fun-function' when +`pcre-mode' is enabled. Returns a function which searches using +emulated PCRE regexps when `isearch-regexp' is true." + (lambda (string bound noerror) + (let ((real-search-function + (funcall (or pcre-old-isearch-search-fun-function 'isearch-search-fun-default)))) + (if (not isearch-regexp) + (funcall real-search-function string bound noerror) + ;; Raise an error if the regexp ends in an incomplete escape + ;; sequence (= odd number of backslashes). + ;; TODO: Perhaps this should really be handled in rxt-pcre-to-elisp? + (if (isearch-backslash string) (rxt-error "Trailing backslash")) + (funcall real-search-function + (pcre-to-elisp/cached string) bound noerror))))) + +(defadvice isearch-message-prefix (after pcre-mode disable) + "Add \"PCRE\" to the Isearch message when searching by regexp in `pcre-mode'." + (when (and isearch-regexp + ;; Prevent an inaccurate message if our callback was + ;; removed somehow + (eq isearch-search-fun-function #'pcre-isearch-search-fun-function)) + (let ((message ad-return-value)) + ;; Some hackery to give replacement the same fontification as + ;; the original + (when + (let ((case-fold-search t)) (string-match "regexp" message)) + (let* ((match (match-string 0 message)) + (properties (text-properties-at 0 match)) + (replacement (apply #'propertize "PCRE regexp" properties)) + (new-message (replace-match replacement t t message))) + (setq ad-return-value new-message)))))) + +(defadvice isearch-fallback + (before pcre-mode (want-backslash &optional allow-invalid to-barrier) disable) + "Hack to fall back correctly in `pcre-mode'. " + ;; A dirty hack to the internals of isearch. Falling back to a + ;; previous match position is necessary when the (Emacs) regexp ends + ;; in "*", "?", "\{" or "\|": this is handled in + ;; `isearch-process-search-char' by calling `isearch-fallback' with + ;; `t' for the value of the first parameter, `want-backslash', in + ;; the last two cases. With PCRE regexps, falling back should take + ;; place on "*", "?", "{" or "|", with no backslashes required. + ;; This advice handles the last two cases by unconditionally setting + ;; `want-backslash' to nil. + (ad-set-arg 0 nil)) + +(defadvice isearch-edit-string + (around pcre-mode disable) + "Add PCRE mode-toggling keys to Isearch minibuffer in regexp mode." + (if isearch-regexp + (minibuffer-with-setup-hook + #'rxt--read-pcre-mode + ad-do-it) + ad-do-it)) + +;;; evil-mode advice +(defadvice evil-search-function + (around pcre-mode (forward regexp-p wrap) disable) + (if (and regexp-p (not isearch-mode)) + (let ((real-search-function ad-do-it)) + (setq ad-return-value + (pcre-decorate-search-function real-search-function))) + ad-do-it)) + +(eval-after-load 'evil + '(when pcre-mode + (ad-enable-advice 'evil-search-function 'around 'pcre-mode) + (ad-activate 'evil-search-function))) + +(defun pcre-decorate-search-function (real-search-function) + (lambda (string &optional bound noerror count) + (funcall real-search-function + (pcre-to-elisp/cached string) + bound noerror count))) + +;;; Other hooks and defadvices + +;;;###autoload +(defun pcre-query-replace-regexp () + "Perform `query-replace-regexp' using PCRE syntax. + +Consider using `pcre-mode' instead of this function." + (interactive) + (let ((old-pcre-mode pcre-mode)) + (unwind-protect + (progn + (pcre-mode +1) + (call-interactively #'query-replace-regexp)) + (pcre-mode (if old-pcre-mode 1 0))))) + + +(defadvice add-to-history + (before pcre-mode (history-var newelt &optional maxelt keep-all) disable) + "Add the original PCRE to query-replace history in `pcre-mode'." + (when (eq history-var query-replace-from-history-variable) + (let ((original (gethash newelt pcre-mode-reverse-cache))) + (when original + (ad-set-arg 1 original))))) + +(defadvice query-replace-descr + (before pcre-mode (from) disable) + "Use the original PCRE in Isearch prompts in `pcre-mode'." + (let ((original (gethash from pcre-mode-reverse-cache))) + (when original + (ad-set-arg 0 original)))) + +;;; The `interactive' specs of the following functions are lifted +;;; wholesale from the original built-ins, which see. +(defadvice read-regexp + (around pcre-mode first (prompt &optional defaults history) disable) + "Read regexp using PCRE syntax and convert to Elisp equivalent." + (ad-set-arg 0 (concat "[PCRE] " prompt)) + (minibuffer-with-setup-hook + #'rxt--read-pcre-mode + ad-do-it) + (setq ad-return-value + (pcre-to-elisp/cached ad-return-value))) + +(defadvice align-regexp + (before pcre-mode first (beg end regexp &optional group spacing repeat) disable) + "Read regexp using PCRE syntax and convert to Elisp equivalent." + (interactive + (append + (list (region-beginning) (region-end)) + (if current-prefix-arg + (list (rxt-pcre-to-elisp + (read-string "Complex align using PCRE regexp: " + "(\\s*)")) + (string-to-number + (read-string + "Parenthesis group to modify (justify if negative): " "1")) + (string-to-number + (read-string "Amount of spacing (or column if negative): " + (number-to-string align-default-spacing))) + (y-or-n-p "Repeat throughout line? ")) + (list (concat "\\(\\s-*\\)" + (rxt-pcre-to-elisp + (read-string "Align PCRE regexp: "))) + 1 align-default-spacing nil))))) + +(defadvice ibuffer-do-replace-regexp + (before pcre-mode first (from-str to-str) disable) + "Read regexp using PCRE syntax and convert to Elisp equivalent." + (interactive + (let* ((from-str (read-from-minibuffer "[PCRE] Replace regexp: ")) + (to-str (read-from-minibuffer (concat "[PCRE] Replace " from-str " with: ")))) + (list (rxt-pcre-to-elisp from-str) to-str)))) + +(defadvice find-tag-regexp + (before pcre-mode first (regexp &optional next-p other-window) disable) + "Read regexp using PCRE syntax and convert to Elisp equivalent. +Perform `find-tag-regexp' using emulated PCRE regexp syntax." + (interactive + (let ((args (find-tag-interactive "[PCRE] Find tag regexp: " t))) + (list (rxt-pcre-to-elisp (nth 0 args)) + (nth 1 args) (nth 2 args))))) + +(defadvice sort-regexp-fields + (before pcre-mode first (reverse record-regexp key-regexp beg end) disable) + "Read regexp using PCRE syntax and convert to Elisp equivalent." + (interactive "P\nsPCRE regexp specifying records to sort: \n\ +sPCRE regexp specifying key within record: \nr") + (ad-set-arg 1 (rxt-pcre-to-elisp (ad-get-arg 1))) + (ad-set-arg 2 (rxt-pcre-to-elisp (ad-get-arg 2)))) + + + +;;; Commands that take Emacs-style regexps as input + +;;;###autoload +(defun rxt-elisp-to-pcre (regexp) + "Translate REGEXP, a regexp in Emacs Lisp syntax, to Perl-compatible syntax. + +Interactively, reads the regexp in one of three ways. With a +prefix arg, reads from minibuffer without string escaping, like +`query-replace-regexp'. Without a prefix arg, uses the text of +the region if it is active. Otherwise, uses the result of +evaluating the sexp before point (which might be a string regexp +literal or an expression that produces a string). + +Displays the translated PCRE regexp in the echo area and copies +it to the kill ring. + +Emacs regexp features such as syntax classes which cannot be +translated to PCRE will cause an error." + (interactive (rxt-interactive/elisp)) + (rxt-return-pcre (rxt-adt->pcre (rxt-parse-elisp regexp)))) + +;;;###autoload +(defun rxt-elisp-to-rx (regexp) + "Translate REGEXP, a regexp in Emacs Lisp syntax, to `rx' syntax. + +See `rxt-elisp-to-pcre' for a description of the interactive +behavior and `rx' for documentation of the S-expression based +regexp syntax." + (interactive (rxt-interactive/elisp)) + (rxt-return-sexp (rxt-adt->rx (rxt-parse-elisp regexp)))) + +;;;###autoload +(defun rxt-elisp-to-strings (regexp) + "Return a list of all strings matched by REGEXP, an Emacs Lisp regexp. + +See `rxt-elisp-to-pcre' for a description of the interactive behavior. + +This is useful primarily for getting back the original list of +strings from a regexp generated by `regexp-opt', but it will work +with any regexp without unbounded quantifiers (*, +, {2, } and so +on). + +Throws an error if REGEXP contains any infinite quantifiers." + (interactive (rxt-interactive/elisp)) + (rxt-return-sexp (rxt-adt->strings (rxt-parse-elisp regexp)))) + +;;;###autoload +(defun rxt-toggle-elisp-rx () + "Toggle the regexp near point between Elisp string and rx syntax." + (interactive) + ;; First, position point before the regex form near point (either + ;; a string literal or a list beginning `rx' or `rx-to-string'). + (let* ((context (syntax-ppss)) + (string-start (nth 8 context))) + (cond (string-start (goto-char string-start)) + ((looking-back "\"") (backward-sexp)) + ((looking-at "\"") nil) + (t + ;; Search backwards, leaving point in place on error + (goto-char + (save-excursion + (skip-syntax-forward "-") + (while (not (looking-at + (rx "(" (or "rx" "rx-to-string") symbol-end))) + (backward-up-list)) + (point)))))) + + ;; Read and replace the regex following point + (let* ((regex (read (current-buffer))) + (print-escape-newlines t)) + (save-excursion + (if (listp regex) + ;; Replace rx form with string value + (prin1 (eval regex) (current-buffer)) + ;; Pretty-print rx form + (save-restriction + (let* ((start (point)) + (rx-syntax (rxt-elisp-to-rx regex)) + (rx-form + (pcase rx-syntax + (`(seq . ,rest) `(rx . ,rest)) + (form `(rx ,form))))) + (rxt-print rx-form) + (narrow-to-region start (point))) + (pp-buffer) + ;; remove the extra newline that pp-buffer inserts + (goto-char (point-max)) + (delete-region + (point) + (save-excursion (skip-chars-backward " \t\n") (point)))))) + (kill-sexp -1) + (indent-pp-sexp))) + + + +;;; Commands that translate PCRE to other formats + +;;;###autoload +(defun rxt-pcre-to-elisp (pcre &optional flags) + "Translate PCRE, a regexp in Perl-compatible syntax, to Emacs Lisp. + +Interactively, uses the contents of the region if it is active, +otherwise reads from the minibuffer. Prints the Emacs translation +in the echo area and copies it to the kill ring. + +PCRE regexp features that cannot be translated into Emacs syntax +will cause an error. See the commentary section of pcre2el.el for +more details." + (interactive (rxt-interactive/pcre)) + (rxt-return-emacs-regexp + (rx-to-string + (rxt-pcre-to-rx (rxt--add-flags pcre flags)) + t))) + +;;;###autoload +(defalias 'pcre-to-elisp 'rxt-pcre-to-elisp) + +;;;###autoload +(defun rxt-pcre-to-rx (pcre &optional flags) + "Translate PCRE, a regexp in Perl-compatible syntax, to `rx' syntax. + +See `rxt-pcre-to-elisp' for a description of the interactive behavior." + (interactive (rxt-interactive/pcre)) + (rxt-return-sexp (rxt-adt->rx (rxt-parse-pcre (rxt--add-flags pcre flags))))) + +;;;###autoload +(defun rxt-pcre-to-strings (pcre &optional flags) + "Return a list of all strings matched by PCRE, a Perl-compatible regexp. + +See `rxt-elisp-to-pcre' for a description of the interactive +behavior and `rxt-elisp-to-strings' for why this might be useful. + +Throws an error if PCRE contains any infinite quantifiers." + (interactive (rxt-interactive/pcre)) + (rxt-return-sexp (rxt-adt->strings (rxt-parse-pcre (rxt--add-flags pcre flags))))) + +(defun rxt--add-flags (pcre flags) + "Prepend FLAGS to PCRE." + (if (not (zerop (length flags))) + (concat "(?" flags ")" pcre) + pcre)) + + +;;; Regexp explaining functions to display pretty-printed rx syntax + +;; When the `rxt-explain' flag is non-nil, `rxt-adt->rx' records +;; location information for each element of the generated `rx' form, +;; allowing highlighting corresponding pieces of syntax at point. +(defvar rxt-explain nil) + +(defvar rxt-highlight-overlays nil + "List of active location-highlighting overlays in rxt-help-mode buffer.") + +;;;###autoload +(defun rxt-explain-elisp (regexp) + "Insert the pretty-printed `rx' syntax for REGEXP in a new buffer. + +REGEXP is a regular expression in Emacs Lisp syntax. See +`rxt-elisp-to-pcre' for a description of how REGEXP is read +interactively." + (interactive (rxt-interactive/elisp)) + (let ((rxt-explain t) + (rxt-verbose-rx-translation rxt-explain-verbosely)) + (rxt-pp-rx regexp (rxt-elisp-to-rx regexp)))) + +;;;###autoload +(defun rxt-explain-pcre (regexp &optional flags) + "Insert the pretty-printed `rx' syntax for REGEXP in a new buffer. + +REGEXP is a regular expression in PCRE syntax. See +`rxt-pcre-to-elisp' for a description of how REGEXP is read +interactively." + (interactive (rxt-interactive/pcre)) + (let ((rxt-explain t) + (rxt-verbose-rx-translation rxt-explain-verbosely)) + (rxt-pp-rx regexp (rxt-pcre-to-rx regexp flags)))) + +;;;###autoload +(defun rxt-quote-pcre (text) + "Return a PCRE regexp which matches TEXT literally. + +Any PCRE metacharacters in TEXT will be quoted with a backslash." + (rxt-adt->pcre (rxt-string text))) + + +;;;; Commands that depend on the major mode in effect + +;; Macro: interactively call one of two functions depending on the +;; major mode +(defmacro rxt-mode-dispatch (elisp-function pcre-function) + `(if (memq major-mode '(emacs-lisp-mode lisp-interaction-mode)) + (call-interactively #',elisp-function) + (call-interactively #',pcre-function))) + +;;;###autoload +(defun rxt-explain () + "Pop up a buffer with pretty-printed `rx' syntax for the regex at point. + +Chooses regex syntax to read based on current major mode, calling +`rxt-explain-elisp' if buffer is in `emacs-lisp-mode' or +`lisp-interaction-mode', or `rxt-explain-pcre' otherwise." + (interactive) + (rxt-mode-dispatch rxt-explain-elisp rxt-explain-pcre)) + +;;;###autoload +(defun rxt-convert-syntax () + "Convert regex at point to other kind of syntax, depending on major mode. + +For buffers in `emacs-lisp-mode' or `lisp-interaction-mode', +calls `rxt-elisp-to-pcre' to convert to PCRE syntax. Otherwise, +calls `rxt-pcre-to-elisp' to convert to Emacs syntax. + +The converted syntax is displayed in the echo area and copied to +the kill ring; see the two functions named above for details." + (interactive) + (rxt-mode-dispatch rxt-elisp-to-pcre rxt-pcre-to-elisp)) + +;;;###autoload +(defun rxt-convert-to-rx () + "Convert regex at point to RX syntax. Chooses Emacs or PCRE syntax by major mode." + (interactive) + (rxt-mode-dispatch rxt-elisp-to-rx rxt-pcre-to-rx)) + +;;;###autoload +(defun rxt-convert-to-strings () + "Convert regex at point to RX syntax. Chooses Emacs or PCRE syntax by major mode." + (interactive) + (rxt-mode-dispatch rxt-elisp-to-strings rxt-pcre-to-strings)) + + + +;;; Minor mode and keybindings + +(defvar rxt-mode-map + (let ((map (make-sparse-keymap))) + ;; Generic + (define-key map (kbd "C-c / /") 'rxt-explain) + (define-key map (kbd "C-c / c") 'rxt-convert-syntax) + (define-key map (kbd "C-c / x") 'rxt-convert-to-rx) + (define-key map (kbd "C-c / '") 'rxt-convert-to-strings) + + ;; From PCRE + (define-key map (kbd "C-c / p /") 'rxt-explain-pcre) + (define-key map (kbd "C-c / p e") 'rxt-pcre-to-elisp) + (define-key map (kbd "C-c / p x") 'rxt-pcre-to-rx) + (define-key map (kbd "C-c / p '") 'rxt-pcre-to-strings) + + ;; From Elisp + (define-key map (kbd "C-c / e /") 'rxt-explain-elisp) + (define-key map (kbd "C-c / e p") 'rxt-elisp-to-pcre) + (define-key map (kbd "C-c / e x") 'rxt-elisp-to-rx) + (define-key map (kbd "C-c / e '") 'rxt-elisp-to-strings) + (define-key map (kbd "C-c / e t") 'rxt-toggle-elisp-rx) + (define-key map (kbd "C-c / t") 'rxt-toggle-elisp-rx) + + ;; Search + (define-key map (kbd "C-c / %") 'pcre-query-replace-regexp) + + map) + "Keymap for `rxt-mode'.") + +;;;###autoload +(define-minor-mode rxt-mode + "Regex translation utilities." nil nil) + +;;;###autoload +(defun turn-on-rxt-mode () + "Turn on `rxt-mode' in the current buffer." + (interactive) + (rxt-mode 1)) + +;;;###autoload +(define-globalized-minor-mode rxt-global-mode rxt-mode + turn-on-rxt-mode) + + +;;;; Syntax explanations + +;; Major mode for displaying pretty-printed S-exp syntax +(define-derived-mode rxt-help-mode emacs-lisp-mode "Regexp Explain" + (setq buffer-read-only t) + (add-hook 'post-command-hook 'rxt-highlight-text nil t) + (rxt-highlight-text)) + +;; Hack: stop paredit-mode interfering with `rxt-print' +(eval-when-compile (declare-function paredit-mode "paredit.el")) +(add-hook 'rxt-help-mode-hook + (lambda () + (if (and (boundp 'paredit-mode) + paredit-mode) + (paredit-mode 0)))) + +(define-key rxt-help-mode-map "q" 'quit-window) +(define-key rxt-help-mode-map "z" 'kill-this-buffer) +(define-key rxt-help-mode-map "n" 'next-line) +(define-key rxt-help-mode-map "p" 'previous-line) +(define-key rxt-help-mode-map "f" 'forward-list) +(define-key rxt-help-mode-map "b" 'backward-list) +(define-key rxt-help-mode-map "u" 'backward-up-list) +(define-key rxt-help-mode-map "d" 'down-list) + +(defvar rxt--print-with-overlays nil) +(defvar rxt--print-depth 0) + +(defconst rxt--print-char-alist + '((?\a . "\\a") + (?\b . "\\b") + (?\t . "\\t") + (?\n . "\\n") + (?\v . "\\v") + (?\f . "\\f") + (?\r . "\\r") + (?\e . "\\e") + (?\s . "\\s") + (?\\ . "\\\\") + (?\d . "\\d")) + "Alist of characters to print using an escape sequence in Elisp source. +See (info \"(elisp) Basic Char Syntax\").") + +(defconst rxt--whitespace-display-regexp + (rx-to-string `(any ,@(mapcar #'car rxt--print-char-alist)))) + +(defconst rxt--print-special-chars + '(?\( ?\) ?\\ ?\| ?\; ?\' ?\` ?\" ?\# ?\. ?\,) + "Characters which require a preceding backslash in Elisp source. +See (info \"(elisp) Basic Char Syntax\").") + +(defun rxt-pp-rx (regexp rx) + "Display string regexp REGEXP with its `rx' form RX in an `rxt-help-mode' buffer." + (with-current-buffer (get-buffer-create "* Regexp Explain *") + (let ((print-escape-newlines t) + (inhibit-read-only t)) + (erase-buffer) + (rxt-help-mode) + (insert (rxt--propertize-whitespace regexp)) + (newline 2) + (save-excursion + (let ((sexp-begin (point)) + (rxt--print-with-overlays t)) + (rxt-print rx) + (narrow-to-region sexp-begin (point)) + (pp-buffer) + (widen))) + (rxt-highlight-text)) + (pop-to-buffer (current-buffer)))) + +(cl-defun rxt-print (rx) + "Insert RX, an `rx' form, into the current buffer, optionally adding overlays. + +Similar to `print' or `prin1', but ensures that `rx' forms are +printed readably, using character or integer syntax depending on +context. + +If `rxt--print-with-overlays' is non-nil, also creates overlays linking +elements of RX to their corresponding locations in the source +string (see `rxt-explain-elisp', `rxt-explain-pcre' and +`rxt--make-help-overlays')." + (let ((start (point))) + (cl-typecase rx + (cons + (pcase rx + (`(,(and (or `repeat `**) head) + ,(and (pred integerp) from) + ,(and (pred integerp) to) + . ,rest) + (insert (format "(%s %d %d" head from to)) + (rxt--print-list-tail rest)) + (`(,(and (or `repeat `= `>=) head) + ,(and (pred integerp) n) + . ,rest) + (insert (format "(%s %d" head n)) + (rxt--print-list-tail rest)) + (_ + (rxt--print-list-tail rx t)))) + (symbol + (cl-case rx + ;; `print' escapes the ? characters in the rx operators *? + ;; and +?, but this looks bad and is not strictly necessary: + ;; (eq (read "*?") (read "*\\?")) => t + ;; (eq (read "+?") (read "+\\?")) => t + ((*? +?) (insert (symbol-name rx))) + (t (prin1 rx (current-buffer))))) + (string + (insert (rxt--propertize-whitespace (prin1-to-string rx)))) + (character + (cond + ((eq ? rx) + (insert "?")) + ((memq rx rxt--print-special-chars) + (insert "?\\" rx)) + ((assq rx rxt--print-char-alist) + (insert "?" (assoc-default rx rxt--print-char-alist))) + (t + (insert "?" (char-to-string rx))))) + (t + (prin1 rx (current-buffer)))) + (when rxt--print-with-overlays + (rxt--make-help-overlays rx start (point))))) + +(defun rxt--print-list-tail (tail &optional open-paren) + (let ((rxt--print-depth (1+ rxt--print-depth))) + (let ((done nil)) + (while (not done) + (cl-typecase tail + (null + (insert ")") + (setq done t)) + (cons + (if open-paren + (progn + (insert "(") + (setq open-paren nil)) + (insert " ")) + (rxt-print (car tail)) + (setq tail (cdr tail))) + (t + (insert " . ") + (rxt-print tail) + (insert ")") + (setq done t))))))) + +(defun rxt--make-help-overlays (rx start end) + (let ((location (rxt-location rx))) + (when (and location + (rxt-location-start location) + (rxt-location-end location)) + (let* ((sexp-begin (copy-marker start t)) + (sexp-end (copy-marker end)) + (sexp-bounds (list sexp-begin sexp-end)) + + (source-begin (1+ (rxt-location-start location))) + (source-end (1+ (rxt-location-end location))) + (source-bounds (list source-begin source-end)) + + (bounds (list source-bounds sexp-bounds)) + + (sexp-ol (make-overlay sexp-begin sexp-end (current-buffer) t nil)) + (source-ol (make-overlay source-begin source-end (current-buffer) t nil))) + (dolist (ol (list sexp-ol source-ol)) + (overlay-put ol 'priority rxt--print-depth) + (overlay-put ol 'rxt-bounds bounds)))))) + +(defun rxt--propertize-whitespace (string) + (let ((string (copy-sequence string)) + (start 0)) + (while (string-match rxt--whitespace-display-regexp string start) + (put-text-property (match-beginning 0) (match-end 0) + 'display + (assoc-default (string-to-char (match-string 0 string)) + rxt--print-char-alist) + string) + (setq start (match-end 0))) + string)) + +(defun rxt-highlight-text () + "Highlight the regex syntax at point and its corresponding RX/string form." + (let ((all-bounds (get-char-property (point) 'rxt-bounds))) + (mapc #'delete-overlay rxt-highlight-overlays) + (setq rxt-highlight-overlays nil) + (dolist (bounds all-bounds) + (cl-destructuring-bind (begin end) bounds + (let ((overlay (make-overlay begin end))) + (push overlay rxt-highlight-overlays) + (overlay-put overlay 'face 'rxt-highlight-face)))))) + + +;;;; Error handling + +(if (fboundp 'define-error) + (define-error 'rxt-invalid-regexp "Invalid regexp" 'invalid-regexp) + (put 'rxt-invalid-regexp + 'error-conditions + '(rxt-invalid-regexp invalid-regexp error)) + (put 'rxt-invalid-regexp 'error-message "Invalid regexp")) + +(defun rxt-error (&rest format-args) + (signal 'rxt-invalid-regexp (list (apply #'format format-args)))) + + +;;;; Regexp syntax tree data type + +;; Base class from which other elements of the syntax-tree inherit +(cl-defstruct rxt-syntax-tree) + +;; Struct representing the original source location +(cl-defstruct rxt-location + source ; Either a string or a buffer + start end ; Offsets, 0- or 1-indexed as appropriate + ) + +(defun rxt-location-text (location) + (if (not (rxt-location-p location)) + nil + (let ((start (rxt-location-start location)) + (end (rxt-location-end location)) + (source (rxt-location-source location))) + (cond + ((buffer-live-p source) + (with-current-buffer source + (buffer-substring-no-properties start end))) + ((stringp source) + (substring source start end)) + (t nil))))) + +;; Hash table mapping from syntax-tree elements to source locations. +(defvar rxt-location-map (make-hash-table :weakness 'key)) + +(defun rxt-location (object) + (gethash object rxt-location-map)) + +(gv-define-setter rxt-location (value object) + `(puthash ,object ,value rxt-location-map)) + +(defun rxt-source-text (object) + (rxt-location-text (rxt-location object))) + +(defun rxt-to-string (tree) + "Return a readable representation of TREE, a regex syntax-tree object." + (or (rxt-source-text tree) + (let ((print-level 1)) + (prin1-to-string tree)))) +(defalias 'rxt-syntax-tree-readable 'rxt-to-string) + +;; FIXME +(defvar rxt-pcre-case-fold nil) + +;; Literal string +(cl-defstruct + (rxt-string + (:constructor rxt-string (chars &optional case-fold)) + (:include rxt-syntax-tree)) + chars + (case-fold rxt-pcre-case-fold)) + +(defun rxt-empty-string () + (rxt-string "")) + +(defun rxt-trivial-p (re) + (and (rxt-string-p re) + (equal (rxt-string-chars re) ""))) + +;;; Other primitives +(cl-defstruct (rxt-primitive + (:constructor rxt-primitive (pcre rx)) + (:include rxt-syntax-tree)) + pcre rx) + +(defun rxt-bos () (rxt-primitive "\\A" 'bos)) +(defun rxt-eos () (rxt-primitive "\\Z" 'eos)) + +(defun rxt-bol () (rxt-primitive "^" 'bol)) +(defun rxt-eol () (rxt-primitive "$" 'eol)) + +;; FIXME +(defun rxt-anything () (rxt-primitive "." 'anything)) +(defun rxt-nonl () (rxt-primitive "." 'nonl)) + +(defun rxt-word-boundary () (rxt-primitive "\\b" 'word-boundary)) +(defun rxt-not-word-boundary () (rxt-primitive "\\B" 'not-word-boundary)) + +(defun rxt-wordchar () (rxt-primitive "\\w" 'wordchar)) +(defun rxt-not-wordchar () (rxt-primitive "\\W" 'not-wordchar)) + +(defun rxt-symbol-start () (rxt-primitive nil 'symbol-start)) +(defun rxt-symbol-end () (rxt-primitive nil 'symbol-end)) + +(defun rxt-bow () (rxt-primitive nil 'bow)) +(defun rxt-eow () (rxt-primitive nil 'eow)) + +;;; Sequence +(cl-defstruct + (rxt-seq + (:constructor make-rxt-seq (elts)) + (:include rxt-syntax-tree)) + elts) + +;; Slightly smart sequence constructor: +;; - Flattens nested sequences +;; - Drops trivial "" elements +;; - Empty sequence => "" +;; - Singleton sequence is reduced to its one element. +(defun rxt-seq (&rest res) ; Flatten nested seqs & drop ""'s. + (let ((res (rxt-seq-flatten res))) + (if (consp res) + (if (consp (cdr res)) + (make-rxt-seq res) ; General case + (car res)) ; Singleton sequence + (rxt-empty-string)))) ; Empty seq -- "" + +(defun rxt-seq-flatten (res) + (if (consp res) + (let ((re (car res)) + (tail (rxt-seq-flatten (cdr res)))) + (cond ((rxt-seq-p re) ; Flatten nested seqs + (append (rxt-seq-flatten (rxt-seq-elts re)) tail)) + ((rxt-trivial-p re) tail) ; Drop trivial elts + ((and (rxt-string-p re) ; Flatten strings + (consp tail) + (rxt-string-p (car tail))) + (cons + (rxt-string-concat re (car tail)) + (cdr tail))) + (t (cons re tail)))) + '())) + +(defun rxt-string-concat (str1 str2) + (if (not (eq (rxt-string-case-fold str1) + (rxt-string-case-fold str2))) + (make-rxt-seq (list str1 str2)) + (let ((result + (rxt-string (concat (rxt-string-chars str1) + (rxt-string-chars str2)) + (rxt-string-case-fold str1))) + (first (rxt-location str1)) + (last (rxt-location str2))) + (when (and first last) + (setf (rxt-location result) + (make-rxt-location :source (rxt-location-source first) + :start (rxt-location-start first) + :end (rxt-location-end last)))) + result))) + +;;; Choice (alternation/union) +(cl-defstruct + (rxt-choice + (:constructor make-rxt-choice (elts)) + (:include rxt-syntax-tree)) + elts) + +;;; The empty choice represents a regexp that never matches in any context +(defvar rxt-empty (make-rxt-choice nil)) +(defun rxt-empty-p (re) + (or + (and (rxt-choice-p re) + (null (rxt-choice-elts re))) + (rxt-empty-char-set-p re))) + +(defun rxt-choice (&rest alternatives) + "Construct the alternation (union) of several regexps. + +ALTERNATIVES should be a list of `rxt-syntax-tree' objects. +The return value is an `rxt-choice' object representing a regexp +which matches any one of ALTERNATIVES, but simplified in the +following ways: + +- If ALTERNATIVES contains only one element, it is returned unchanged. + +- All existing `rxt-choice' elements in ALTERNATIVES are replaced + by a flat list of their subexpressions: symbolically, + a|(b|(c|d)) is replaced by a|b|c|d + +- All character sets and single-character strings in ALTERNATIVES + are combined together into one or two character sets, + respecting case-folding behaviour." + (cl-destructuring-bind (other-elements char-set case-fold-char-set) + (rxt--simplify-alternatives alternatives) + (let ((simplified-alternatives + (append (if (not (rxt-empty-p char-set)) + (list char-set) + '()) + (if (not (rxt-empty-p case-fold-char-set)) + (list case-fold-char-set) + '()) + other-elements))) + (pcase simplified-alternatives + (`() + rxt-empty) + (`(,element) + element) + (_ + (make-rxt-choice simplified-alternatives)))))) + +(defun rxt--simplify-alternatives (alternatives) + "Simplify a set of regexp alternatives. + +ALTERNATIVES should be a list of `rxt-syntax-tree' objects to be combined +into an `rxt-choice' structure. The result is a three-element +list (OTHER-ELEMENTS CHAR-SET CASE-FOLDED-CHAR-SET): + +- CHAR-SET is an `rxt-char-set-union' containing the union of all + case-sensitive character sets and single-character strings in + RES. + +- CASE-FOLDED-CHAR-SET is similar but combines all the + case-insensitive character sets and single-character strings. + +- OTHER-ELEMENTS is a list of all other elements, with all + `rxt-choice' structures replaced by a flat list of their + component subexpressions." + (if (null alternatives) + (list '() + (make-rxt-char-set-union :case-fold nil) + (make-rxt-char-set-union :case-fold t)) + (let* ((re (car alternatives))) + (cl-destructuring-bind (tail char-set case-fold-char-set) + (rxt--simplify-alternatives (cdr alternatives)) + (cond ((rxt-choice-p re) ; Flatten nested choices + (list + (append (rxt-choice-elts re) tail) + char-set + case-fold-char-set)) + + ((rxt-empty-p re) ; Drop empty re's. + (list tail char-set case-fold-char-set)) + + ((rxt-char-set-union-p re) ; Fold char sets together + (if (rxt-char-set-union-case-fold re) + (list tail + char-set + (rxt-char-set-union case-fold-char-set re)) + (list tail + (rxt-char-set-union char-set re) + case-fold-char-set))) + + ((and (rxt-string-p re) ; Same for 1-char strings + (= 1 (length (rxt-string-chars re)))) + (if (rxt-string-case-fold re) + (list tail + char-set + (rxt-char-set-union case-fold-char-set re)) + (list tail + (rxt-char-set-union char-set re) + case-fold-char-set))) + + (t ; Otherwise. + (list (cons re tail) char-set case-fold-char-set))))))) + +;;; Repetition +(cl-defstruct (rxt-repeat + (:include rxt-syntax-tree)) + from to body greedy) + +(cl-defun rxt-repeat (from to body &optional (greedy t)) + (if (equal to 0) + (rxt-empty-string) + (make-rxt-repeat :from from :to to + :body body :greedy greedy))) + +;;; Submatch +(cl-defstruct + (rxt-submatch + (:constructor rxt-submatch (body)) + (:include rxt-syntax-tree)) + body) + +;;; Numbered submatch (Emacs only) +(cl-defstruct + (rxt-submatch-numbered + (:constructor rxt-submatch-numbered (n body)) + (:include rxt-syntax-tree)) + n + body) + +;;; Backreference +(cl-defstruct + (rxt-backref + (:constructor rxt-backref (n)) + (:include rxt-syntax-tree)) + n) + +;;; Syntax classes (Emacs only) +(cl-defstruct (rxt-syntax-class + (:include rxt-syntax-tree)) + symbol) + +(defun rxt-syntax-class (symbol) + (if (assoc symbol rx-syntax) + (make-rxt-syntax-class :symbol symbol) + (rxt-error "Invalid syntax class symbol `%s'" symbol))) + +;;; Character categories (Emacs only) +(cl-defstruct (rxt-char-category + (:include rxt-syntax-tree)) + symbol) + +(defun rxt-char-category (symbol) + (if (assoc symbol rx-categories) + (make-rxt-char-category :symbol symbol) + (rxt-error "Invalid character category symbol `%s'" symbol))) + + +;;; Char sets +;; ::= +;; | +;; | + +(cl-defstruct (rxt-char-set (:include rxt-syntax-tree))) + +;; An rxt-char-set-union represents the union of any number of +;; characters, character ranges, and POSIX character classes: anything +;; that can be represented in string notation as a class [ ... ] +;; without the negation operator. +(cl-defstruct (rxt-char-set-union + (:include rxt-char-set)) + chars ; list of single characters + ranges ; list of ranges (from . to) + classes ; list of character classes + (case-fold rxt-pcre-case-fold)) + +;; Test for empty character set +(defun rxt-empty-char-set-p (cset) + (and (rxt-char-set-union-p cset) + (null (rxt-char-set-union-chars cset)) + (null (rxt-char-set-union-ranges cset)) + (null (rxt-char-set-union-classes cset)))) + +;; Simple union constructor +(defun rxt-char-set-union (&rest items) + "Construct an regexp character set representing the union of ITEMS. + +Each element of ITEMS may be either: a character; a +single-character string; a single-character `rxt-string' object; +a cons, (FROM . TO) representing a range of characters; a symbol, +representing a named character class; or an `rxt-char-set-union' +object. All `rxt-char-set-union' objects in ITEMS must have the +same `case-fold' property." + (let ((chars '()) + (ranges '()) + (classes '()) + (case-fold 'undetermined)) + (dolist (item items) + (cl-etypecase item + (character + (push item chars)) + + (string + (cl-assert (= 1 (length item))) + (push (string-to-char item) chars)) + + (rxt-string + (cl-assert (= 1 (length (rxt-string-chars item)))) + (push (string-to-char (rxt-string-chars item)) chars)) + + (cons ; range (from . to) + (cl-check-type (car item) character) + (cl-check-type (cdr item) character) + (push item ranges)) + + (symbol ; named character class + (push item classes)) + + (rxt-char-set-union + (if (eq case-fold 'undetermined) + (setq case-fold (rxt-char-set-union-case-fold item)) + (unless (eq case-fold (rxt-char-set-union-case-fold item)) + (error "Cannot construct union of char-sets with unlike case-fold setting: %S" item))) + (setq chars (nconc chars (rxt-char-set-union-chars item))) + (setq ranges (nconc ranges (rxt-char-set-union-ranges item))) + (setq classes (nconc classes (rxt-char-set-union-classes item)))))) + + (make-rxt-char-set-union :chars chars :ranges ranges :classes classes + :case-fold (if (eq case-fold 'undetermined) + rxt-pcre-case-fold + case-fold)))) + +(defun rxt--all-char-set-union-chars (char-set) + "Return a list of all characters in CHAR-SET." + (cl-assert (rxt-char-set-union-p char-set)) + (append + (rxt-char-set-union-chars char-set) + (cl-loop for (start . end) in (rxt-char-set-union-ranges char-set) + nconc (cl-loop for char from start to end collect char)))) + +(defun rxt--simplify-char-set (char-set &optional case-fold-p) + "Return a minimal char-set to match the same characters as CHAR-SET. + +With optional argument CASE-FOLD-P, return a char-set which +emulates case-folding behaviour by including both uppercase and +lowercase versions of all characters in CHAR-SET." + (cl-assert (rxt-char-set-union-p char-set)) + (let* ((classes (rxt-char-set-union-classes char-set)) + (all-chars + (if case-fold-p + (cl-loop for char in (rxt--all-char-set-union-chars char-set) + nconc (list (upcase char) (downcase char))) + (rxt--all-char-set-union-chars char-set))) + (all-ranges + (rxt--extract-ranges (rxt--remove-redundant-chars all-chars classes)))) + (let ((singletons nil) + (ranges nil)) + (cl-loop for (start . end) in all-ranges + do + (cond ((= start end) (push start singletons)) + ((= (1+ start) end) + (push start singletons) + (push end singletons)) + (t (push (cons start end) ranges)))) + (make-rxt-char-set-union :chars (nreverse singletons) + :ranges (nreverse ranges) + :classes classes + :case-fold (if case-fold-p + nil + (rxt-char-set-union-case-fold char-set)))))) + +(defun rxt--remove-redundant-chars (chars classes) + "Remove all characters which match a character class in CLASSES from CHARS." + (if (null classes) + chars + (string-to-list + (replace-regexp-in-string + (rx-to-string `(any ,@classes)) + "" + (apply #'string chars))))) + +(defun rxt--extract-ranges (chars) + "Return a list of all contiguous ranges in CHARS. + +CHARS should be a list of characters (integers). The return +value is a list of conses (START . END) representing ranges, such +that the union of all the ranges represents the same of +characters as CHARS. + +Example: + (rxt--extract-ranges (list ?a ?b ?c ?q ?x ?y ?z)) + => ((?a . ?c) (?q . ?q) (?x . ?z))" + (let ((array + (apply #'vector + (cl-remove-duplicates + (sort (copy-sequence chars) #'<))))) + (cl-labels + ((recur (start end) + (if (< end start) + nil + (let ((min (aref array start)) + (max (aref array end))) + (if (= (- max min) (- end start)) + (list (cons min max)) + (let* ((split-point (/ (+ start end) 2)) + (left (recur start split-point)) + (right (recur (1+ split-point) end))) + (merge left right)))))) + (merge (left right) + (cond ((null left) right) + ((null right) left) + (t + (let ((last-left (car (last left))) + (first-right (car right))) + (if (= (1+ (cdr last-left)) + (car first-right)) + (append (cl-subseq left 0 -1) + (list + (cons (car last-left) + (cdr first-right))) + (cl-subseq right 1)) + (append left right))))))) + (recur 0 (1- (length array)))))) + +;;; Set complement of character set, syntax class, or character +;;; category + +;; In general, all character sets that can be represented in string +;; notation as [^ ... ] (but see `rxt-char-set-intersection', below), plus +;; Emacs' \Sx and \Cx constructions. +(cl-defstruct (rxt-char-set-negation + (:include rxt-char-set)) + elt) + +(defun rxt-negate (char-set) + "Construct the logical complement (negation) of CHAR-SET. + +CHAR-SET may be any of the following types: `rxt-char-set-union', +`rxt-syntax-class', `rxt-char-category', or `rxt-char-set-negation'." + (cl-etypecase char-set + ((or rxt-char-set-union rxt-syntax-class rxt-char-category) + (make-rxt-char-set-negation :elt char-set)) + + (rxt-char-set-negation + (rxt-char-set-negation-elt char-set)))) + +;;; Intersections of char sets + +;; These are difficult to represent in general, but can be constructed +;; in Perl using double negation; for example: [^\Wabc] means the set +;; complement of [abc] with respect to the universe of "word +;; characters": (& (~ (~ word)) (~ ("abc"))) == (& word (~ ("abc"))) +;; == (- word ("abc")) + +(cl-defstruct (rxt-char-set-intersection + (:include rxt-char-set)) + elts) + +;; Intersection constructor +(defun rxt-char-set-intersection (&rest charsets) + (let ((elts '()) + (cmpl (make-rxt-char-set-union))) + (dolist (cset (rxt-int-flatten charsets)) + (cond + ((rxt-char-set-negation-p cset) + ;; Fold negated charsets together: ~A & ~B = ~(A|B) + (setq cmpl (rxt-char-set-union cmpl (rxt-char-set-negation-elt cset)))) + + ((rxt-char-set-union-p cset) + (push cset elts)) + + (t + (rxt-error "Can't take intersection of non-character-set %S" cset)))) + + (if (null elts) + (rxt-negate cmpl) + (unless (rxt-empty-char-set-p cmpl) + (push (rxt-negate cmpl) elts)) + (if (null (cdr elts)) + (car elts) ; singleton case + (make-rxt-char-set-intersection :elts elts))))) + +;; Constructor helper: flatten nested intersections +(defun rxt-int-flatten (csets) + (if (consp csets) + (let ((cset (car csets)) + (tail (rxt-int-flatten (cdr csets)))) + (if (rxt-char-set-intersection-p cset) + (append (rxt-int-flatten (rxt-char-set-intersection-elts cset)) tail) + (cons cset tail))) + '())) + + + +;;;; Macros for building the parser + +(defmacro rxt-token-case (&rest cases) + "Consume a token at point and evaluate corresponding forms. + +CASES is a list of `cond'-like clauses, (REGEXP BODY ...) where +the REGEXPs define possible tokens which may appear at point. The +CASES are considered in order. For each case, if the text at +point matches REGEXP, then point is moved to the end of the +matched token, the corresponding BODY is evaluated and their +value returned. The matched token is available within the BODY +forms as (match-string 0). + +There can be a default case where REGEXP is `t', which evaluates +the corresponding FORMS but does not move point. + +Returns `nil' if none of the CASES matches." + (declare (debug (&rest (sexp &rest form)))) + `(cond + ,@(cl-loop for (token . action) in cases + collect + (if (eq token t) + `(t ,@action) + `((looking-at ,token) + (goto-char (match-end 0)) + ,@action))))) + +(defmacro rxt-with-source-location (&rest body) + "Evaluate BODY and record source location information on its value. + +BODY may evaluate to any kind of object, but its value should +generally not be `eq' to any other object." + (declare (debug (&rest form))) + (let ((begin (make-symbol "begin")) + (value (make-symbol "value"))) + `(let ((,begin (point)) + (,value ,(macroexp-progn body))) + (setf (rxt-location ,value) + (make-rxt-location :source rxt-source-text-string + :start (1- ,begin) + :end (1- (point)))) + ,value))) + +;; Read PCRE + flags +(defun rxt-read-delimited-pcre () + "Read a Perl-style delimited regexp and flags from the current buffer. + +Point should be before the regexp literal before calling +this. Currently only regexps delimited by / ... / are supported. +A preceding \"m\", \"qr\" or \"s\" will be ignored, as will the +replacement string in an s/.../.../ construction. + +Returns two strings: the regexp and the flags." + (save-excursion + (skip-syntax-forward "-") + + ;; Skip m, qr, s + (let ((is-subst (rxt-token-case + ("s" t) + ((rx (or "m" "qr")) nil)))) + + (when (not (looking-at "/")) + (error "Only Perl regexps delimited by slashes are supported")) + (let ((beg (match-end 0)) + (delim (rx (not (any "\\")) + (group "/")))) + (search-forward-regexp delim) + (let ((end (match-beginning 1))) + (when is-subst (search-forward-regexp delim)) + (let ((pcre (buffer-substring-no-properties beg end))) + (rxt-token-case + ("[gimosx]*" + (rxt--add-flags pcre (match-string-no-properties 0)))))))))) + + +;;;; Elisp and PCRE string notation parser + +;;; Parser constants +(defconst rxt-pcre-char-set-alist + `((?w . ; "word" characters + (?_ alnum)) + (?d . ; digits + (digit)) + (?h . ; horizontal whitespace + (#x0009 #x0020 #x00A0 #x1680 #x180E #x2000 #x2001 #x2002 #x2003 + #x2004 #x2005 #x2006 #x2007 #x2008 #x2009 #x200A #x202F + #x205F #x3000)) + (?s . ; whitespace + (9 10 12 13 32)) + (?v . ; vertical whitespace + (#x000A #x000B #x000C #x000D #x0085 #x2028 #x2029)))) + +(defconst rxt-pcre-named-classes-regexp + (rx "[:" + (submatch + (or "alnum" "alpha" "ascii" "blank" "cntrl" "digit" "graph" "lower" + "print" "punct" "space" "upper" "word" "xdigit")) + ":]")) + +(defconst rxt-elisp-named-classes-regexp + (rx "[:" + (submatch + (or "alnum" "alpha" "ascii" "blank" "cntrl" "digit" "graph" "lower" + "print" "punct" "space" "upper" "word" "xdigit" + "unibyte" "nonascii" "multibyte")) + ":]")) + +;;; The following dynamically bound variables control the operation of +;;; the parser (see `rxt-parse-re'.) +(defvar rxt-parse-pcre nil + "t if the rxt string parser is parsing PCRE syntax, nil for Elisp syntax. + +This should only be let-bound internally, never set otherwise.") + +(defvar rxt-pcre-extended-mode nil + "t if the rxt string parser is emulating PCRE's \"extended\" mode. + +In extended mode (indicated by /x in Perl/PCRE), whitespace +outside of character classes and \\Q...\\E quoting is ignored, +and a `#' character introduces a comment that extends to the end +of line.") + +(defvar rxt-pcre-s-mode nil + "t if the rxt string parser is emulating PCRE's single-line \"/s\" mode. + +When /s is used, PCRE's \".\" matches newline characters, which +otherwise it would not match.") + +(defvar rxt-pcre-case-fold nil + "non-nil to emulate PCRE's case-insensitive \"/i\" mode in translated regexps.") + +(defvar rxt-branch-end-regexp nil) +(defvar rxt-choice-regexp nil) +(defvar rxt-brace-begin-regexp nil) +(defvar rxt-m-to-n-brace-regexp nil) +(defvar rxt-m-to-?-brace-regexp nil) +(defvar rxt-m-brace-regexp nil) +(defvar rxt-named-classes-regexp nil) + +(defvar rxt-subgroup-count nil) +(defvar rxt-source-text-string nil) + +(defun rxt-parse-pcre (re) + (rxt-parse-re re t)) + +(defun rxt-parse-elisp (re) + (rxt-parse-re re nil)) + +(defun rxt-parse-re (re pcre-p) + (let* ((rxt-parse-pcre pcre-p) + (rxt-pcre-extended-mode nil) + (rxt-pcre-s-mode nil) + (rxt-pcre-case-fold nil) + + ;; Bind regexps to match syntax that differs between PCRE and + ;; Elisp only in the addition of a backslash "\" + (escape (if pcre-p "" "\\")) + (rxt-choice-regexp + (rx-to-string `(seq ,escape "|"))) + (rxt-branch-end-regexp + (rx-to-string `(or buffer-end + (seq ,escape (or "|" ")"))))) + (rxt-brace-begin-regexp + (rx-to-string `(seq ,escape "{"))) + (rxt-m-to-n-brace-regexp + (rx-to-string + `(seq + (submatch (* (any "0-9"))) "," (submatch (+ (any "0-9"))) + ,escape "}"))) + (rxt-m-to-?-brace-regexp + (rx-to-string + `(seq (submatch (+ (any "0-9"))) "," ,escape "}"))) + (rxt-m-brace-regexp + (rx-to-string + `(seq (submatch (+ (any "0-9"))) ,escape "}"))) + + ;; Named character classes [: ... :] differ slightly + (rxt-named-classes-regexp + (if pcre-p + rxt-pcre-named-classes-regexp + rxt-elisp-named-classes-regexp)) + + (rxt-subgroup-count 0) + (case-fold-search nil)) + (with-temp-buffer + (insert re) + (goto-char (point-min)) + (let ((rxt-source-text-string re)) + (rxt-parse-exp))))) + +;; Parse a complete regex: a number of branches separated by | or +;; \|, as determined by `rxt-branch-end-regexp'. +(defun rxt-parse-exp () + ;; These variables are let-bound here because in PCRE mode they may + ;; be set internally by (?x) or (?s) constructions, whose scope + ;; lasts until the end of a sub-expression + (rxt-with-source-location + (let ((rxt-pcre-extended-mode rxt-pcre-extended-mode) + (rxt-pcre-s-mode rxt-pcre-s-mode) + (rxt-pcre-case-fold rxt-pcre-case-fold)) + (if (eobp) + (rxt-seq) + (let ((branches '())) + (cl-block nil + (while t + (let ((branch (rxt-parse-branch))) + (push branch branches) + (rxt-token-case + (rxt-choice-regexp nil) + (t (cl-return (apply #'rxt-choice (reverse branches))))))))))))) + +;; Skip over whitespace and comments in PCRE extended mode +(defun rxt-extended-skip () + (when rxt-pcre-extended-mode + (skip-syntax-forward "-") + (while (looking-at "#") + (beginning-of-line 2) + (skip-syntax-forward "-")))) + +;; Parse a regexp "branch": a sequence of pieces +(defun rxt-parse-branch () + (rxt-extended-skip) + (rxt-with-source-location + (let ((pieces '()) + (branch-start-p t)) + (while (not (looking-at rxt-branch-end-regexp)) + (push (rxt-parse-piece branch-start-p) pieces) + (setq branch-start-p nil)) + (apply #'rxt-seq (reverse pieces))))) + +;; Parse a regexp "piece": an atom (`rxt-parse-atom') plus any +;; following quantifiers +(defun rxt-parse-piece (&optional branch-begin) + (rxt-extended-skip) + (rxt-with-source-location + (let ((atom (rxt-parse-atom branch-begin))) + (rxt-parse-quantifiers atom)))) + +;; Parse any and all quantifiers after ATOM and return the quantified +;; regexp, or ATOM unchanged if no quantifiers +(defun rxt-parse-quantifiers (atom) + (catch 'done + (while (not (eobp)) + (let ((atom1 (rxt-parse-quantifier atom))) + (if (eq atom1 atom) + (throw 'done t) + (setq atom atom1))))) + atom) + +;; Possibly parse a single quantifier after ATOM and return the +;; quantified atom, or ATOM if no quantifier +(defun rxt-parse-quantifier (atom) + (rxt-extended-skip) + (rxt-token-case + ((rx "*?") (rxt-repeat 0 nil atom nil)) + ((rx "*") (rxt-repeat 0 nil atom t)) + ((rx "+?") (rxt-repeat 1 nil atom nil)) + ((rx "+") (rxt-repeat 1 nil atom t)) + ((rx "??") (rxt-repeat 0 1 atom nil)) + ((rx "?") (rxt-repeat 0 1 atom t)) + ;; Brace expression "{M,N}", "{M,}", "{M}" + (rxt-brace-begin-regexp + (cl-destructuring-bind (from to) + (rxt-parse-braces) + (rxt-repeat from to atom))) + ;; No quantifiers found + (t atom))) + +;; Parse a regexp atom, i.e. an element that binds to any following +;; quantifiers. This includes characters, character classes, +;; parenthesized groups, assertions, etc. +(defun rxt-parse-atom (&optional branch-begin) + (if (eobp) + (rxt-error "Unexpected end of regular expression") + (if rxt-parse-pcre + (rxt-parse-atom/pcre) + (rxt-parse-atom/el branch-begin)))) + +(defun rxt-parse-atom/common () + (rxt-token-case + ((rx "[") (rxt-parse-char-class)) + ((rx "\\b") (rxt-word-boundary)) + ((rx "\\B") (rxt-not-word-boundary)))) + +(defun rxt-parse-atom/el (branch-begin) + (rxt-with-source-location + (or (rxt-parse-atom/common) + (rxt-token-case + ;; "." wildcard + ((rx ".") (rxt-nonl)) + ;; "^" and "$" are metacharacters only at beginning or end of a + ;; branch in Elisp; elsewhere they are literals + ((rx "^") + (if branch-begin + (rxt-bol) + (rxt-string "^"))) + ((rx "$") + (if (looking-at rxt-branch-end-regexp) + (rxt-eol) + (rxt-string "$"))) + ;; Beginning & end of string, word, symbol + ((rx "\\`") (rxt-bos)) + ((rx "\\'") (rxt-eos)) + ((rx "\\<") (rxt-bow)) + ((rx "\\>") (rxt-eow)) + ((rx "\\_<") (rxt-symbol-start)) + ((rx "\\_>") (rxt-symbol-end)) + ;; Subgroup + ((rx "\\(") (rxt-parse-subgroup/el)) + ;; Word/non-word characters (meaning depending on syntax table) + ((rx "\\w") (rxt-wordchar)) + ((rx "\\W") (rxt-not-wordchar)) + ;; Other syntax categories + ((rx "\\" (submatch (any ?S ?s)) (submatch nonl)) + (let ((negated (string= (match-string 1) "S")) + (syntax + (car (rassoc (string-to-char (match-string 2)) + rx-syntax)))) + (if syntax + (let ((re (rxt-syntax-class syntax))) + (if negated (rxt-negate re) re)) + (rxt-error "Invalid syntax class `\\%s'" (match-string 0))))) + ;; Character categories + ((rx "\\" (submatch (any ?C ?c)) (submatch nonl)) + (let ((negated (string= (match-string 1) "C")) + (category + (car (rassoc (string-to-char (match-string 2)) + rx-categories)))) + (if category + (let ((re (rxt-char-category category))) + (if negated (rxt-negate re) re)) + (rxt-error "Invalid character category `%s'" (match-string 0))))) + ;; Backreference + ((rx (seq "\\" (submatch (any "1-9")))) + (rxt-backref (string-to-number (match-string 1)))) + ;; Other escaped characters + ((rx (seq "\\" (submatch nonl))) + (rxt-string (match-string 1))) + ;; Normal characters + ((rx (or "\n" nonl)) + (rxt-string (match-string 0))))))) + +(defun rxt-parse-atom/pcre () + (rxt-extended-skip) + (rxt-with-source-location + (or + ;; Is it an atom that's the same in Elisp? + (rxt-parse-atom/common) + ;; Is it common to PCRE regex and character class syntax? + (let ((char (rxt-parse-escapes/pcre))) + (and char + (rxt-string (char-to-string char)))) + ;; Otherwise: + (rxt-token-case + ;; "." wildcard + ((rx ".") + (if rxt-pcre-s-mode + (rxt-anything) + (rxt-nonl))) + ;; Beginning & end of string/line + ((rx "^") (rxt-bol)) + ((rx "$") (rxt-eol)) + ((rx "\\A") (rxt-bos)) + ((rx "\\Z") (rxt-eos)) + ;; Subgroup + ((rx "(") (rxt-parse-subgroup/pcre)) + ;; Metacharacter quoting + ((rx "\\Q") + ;; It would seem simple to take all the characters between \Q + ;; and \E and make an rxt-string, but \Q...\E isn't an atom: + ;; any quantifiers afterward should bind only to the last + ;; character, not the whole string. + (let ((begin (point))) + (search-forward "\\E" nil t) + (let* ((end (match-beginning 0)) + (str (buffer-substring-no-properties begin (1- end))) + (char (char-to-string (char-before end)))) + (rxt-seq (rxt-string str) + (rxt-parse-quantifiers (rxt-string char)))))) + ;; Pre-defined character sets + ((rx "\\" (submatch (any "d" "D" "h" "H" "s" "S" "v" "V" "w" "W"))) + (rxt--pcre-char-set (string-to-char (match-string 1)))) + ;; \ + digits: backreference or octal char? + ((rx "\\" (submatch (+ (any "0-9")))) + (let* ((digits (match-string 1)) + (dec (string-to-number digits))) + ;; from "man pcrepattern": If the number is less than 10, or if + ;; there have been at least that many previous capturing left + ;; parentheses in the expression, the entire sequence is taken + ;; as a back reference. + (if (and (> dec 0) + (or (< dec 10) + (>= rxt-subgroup-count dec))) + (progn + (when rxt-pcre-case-fold + (display-warning + 'rxt "Backreferences with case-folding are handled poorly")) + (rxt-backref dec)) + ;; from "man pcrepattern": if the decimal number is greater + ;; than 9 and there have not been that many capturing + ;; subpatterns, PCRE re-reads up to three octal digits + ;; following the backslash, and uses them to generate a data + ;; character. Any subsequent digits stand for themselves. + (goto-char (match-beginning 1)) + (re-search-forward (rx (** 0 3 (any "0-7")))) + (rxt-string (char-to-string (string-to-number (match-string 0) 8)))))) + ;; Other escaped characters + ((rx "\\" (submatch nonl)) (rxt-string (match-string 1))) + ;; Everything else + ((rx (or (any "\n") nonl)) (rxt-string (match-string 0))))))) + +(defun rxt-parse-escapes/pcre () + "Consume a one-char PCRE escape at point and return its codepoint equivalent. + +Handles only those character escapes which have the same meaning +in character classes as outside them." + (rxt-token-case + ((rx "\\a") #x07) ; bell + ((rx "\\e") #x1b) ; escape + ((rx "\\f") #x0c) ; formfeed + ((rx "\\n") #x0a) ; linefeed + ((rx "\\r") #x0d) ; carriage return + ((rx "\\t") #x09) ; tab + ;; Control character + ((rx "\\c" (submatch nonl)) + ;; from `man pcrepattern': + ;; The precise effect of \cx is as follows: if x is a lower case + ;; letter, it is converted to upper case. Then bit 6 of the + ;; character (hex 40) is inverted. + (logxor (string-to-char (upcase (match-string 1))) #x40)) + ;; Hex escapes + ((rx "\\x" (submatch (** 1 2 (any "0-9" "A-Z" "a-z")))) + (string-to-number (match-string 1) 16)) + ((rx "\\x{" (submatch (* (any "0-9" "A-Z" "a-z"))) "}") + (string-to-number (match-string 1) 16)))) + +(defun rxt-parse-subgroup/pcre () + (catch 'return + (let ((shy nil) + (extended-mode rxt-pcre-extended-mode) + (single-line-mode rxt-pcre-s-mode) + (case-fold rxt-pcre-case-fold)) + (rxt-extended-skip) + ;; Check for special (? ..) and (* ...) syntax + (rxt-token-case + ((rx "?") ; (? + (rxt-token-case + ((rx ")") ; Empty group (?) + (throw 'return (rxt-empty-string))) + (":" (setq shy t)) ; Shy group (?: + ("#" ; Comment (?# + (search-forward ")") + (throw 'return (rxt-empty-string))) + ((rx (or ; Flags (?isx-isx + (seq (group (* (any "gimosx"))) "-" (group (+ (any "gimosx")))) + (seq (group (+ (any "gimosx")))))) + (let ((token (match-string 0)) + (on (or (match-string 1) (match-string 3))) + (off (or (match-string 2) ""))) + (if (cl-find ?x on) (setq extended-mode t)) + (if (cl-find ?s on) (setq single-line-mode t)) + (if (cl-find ?i on) (setq case-fold t)) + (if (cl-find ?x off) (setq extended-mode nil)) + (if (cl-find ?s off) (setq single-line-mode nil)) + (if (cl-find ?i off) (setq case-fold nil)) + (when (string-match-p "[gmo]" token) + (display-warning + 'rxt (format "Unhandled PCRE flags in (?%s" token)))) + (rxt-token-case + (":" (setq shy t)) ; Shy group with flags (?isx-isx: ... + (")" ; Set flags (?isx-isx) + ;; Set flags for the remainder of the current subexpression + (setq rxt-pcre-extended-mode extended-mode + rxt-pcre-s-mode single-line-mode + rxt-pcre-case-fold case-fold) + (throw 'return (rxt-empty-string))))) + ;; Other constructions like (?=, (?!, etc. are not recognised + (t (rxt-error "Unrecognized PCRE extended construction `(?%c'" + (char-after))))) + + ;; No special (* ...) verbs are recognised + ((rx "*") + (let ((begin (point))) + (search-forward ")" nil 'go-to-end) + (rxt-error "Unrecognized PCRE extended construction `(*%s'" + (buffer-substring begin (point)))))) + + ;; Parse the remainder of the subgroup + (unless shy (cl-incf rxt-subgroup-count)) + (let* ((rxt-pcre-extended-mode extended-mode) + (rxt-pcre-s-mode single-line-mode) + (rxt-pcre-case-fold case-fold) + (rx (rxt-parse-exp))) + (rxt-extended-skip) + (rxt-token-case + (")" (if shy rx (rxt-submatch rx))) + (t (rxt-error "Subexpression missing close paren"))))))) + +(defun rxt-parse-subgroup/el () + (let ((kind + (rxt-token-case + ((rx "?:") + (cl-incf rxt-subgroup-count) + 'shy) + ((rx "?" (group (+ (in "0-9"))) ":") + (let ((n (string-to-number (match-string 1)))) + (when (< rxt-subgroup-count n) + (setf rxt-subgroup-count n)) + n)) + ((rx "?") ; Reserved + (rxt-error "Unknown match group sequence"))))) + (let ((rx (rxt-parse-exp))) + (rxt-token-case + ((rx "\\)") + (cond ((eq kind 'shy) rx) + ((numberp kind) + (rxt-submatch-numbered kind rx)) + (t (rxt-submatch rx)))) + (t (rxt-error "Subexpression missing close paren")))))) + +(defun rxt-parse-braces () + (rxt-token-case + (rxt-m-to-n-brace-regexp + (list (string-to-number (match-string 1)) + (string-to-number (match-string 2)))) + (rxt-m-to-?-brace-regexp + (list (string-to-number (match-string 1)) nil)) + (rxt-m-brace-regexp + (let ((a (string-to-number (match-string 1)))) + (list a a))) + (t + (let ((begin (point))) + (search-forward "}" nil 'go-to-end) + (rxt-error "Bad brace expression {%s" + (buffer-substring-no-properties begin (point))))))) + +;; Parse a character set range [...] +(defun rxt-parse-char-class () + (when (eobp) + (rxt-error "Missing close right bracket in regexp")) + (rxt-with-source-location + (let* ((negated (rxt-token-case + ((rx "^") t) + (t nil))) + (begin (point)) + (result + (if negated + (rxt-negate (rxt-char-set-union)) + (rxt-char-set-union))) + (transformer + (if negated #'rxt-negate #'identity)) + (builder + (if negated #'rxt-char-set-intersection #'rxt-choice))) + (catch 'done + (while t + (when (eobp) + (rxt-error "Missing close right bracket in regexp")) + (if (and (looking-at (rx "]")) + (not (= (point) begin))) + (throw 'done result) + (let ((piece (funcall transformer (rxt-parse-char-class-piece)))) + (setq result (funcall builder result piece)))))) + (forward-char) ; Skip over closing "]" + result))) + +;; Parse a single character, a character range, or a posix class +;; within a character set context. Returns an `rxt-char-set'. +(defun rxt-parse-char-class-piece () + (let ((atom (rxt-parse-char-class-atom))) + (cl-typecase atom + (rxt-char-set ; return unchanged + atom) + (integer ; character: check for range + (let ((range-end (rxt-maybe-parse-range-end))) + (if range-end + (rxt-char-set-union (cons atom range-end)) + (rxt-char-set-union atom)))) + (t ; transform into character set + (rxt-char-set-union atom))))) + +;; Parse a single character or named class within a charset. +;; +;; Returns an integer (a character), a symbol (representing a named +;; character class) or an `rxt-char-set' (for pre-defined character +;; classes like \d, \W, etc.) +(defun rxt-parse-char-class-atom () + (or + ;; First, check for PCRE-specific backslash sequences + (and rxt-parse-pcre + (rxt-parse-char-class-atom/pcre)) + ;; Char-class syntax + (rxt-token-case + ;; Named classes [:alnum:], ... + (rxt-named-classes-regexp + (intern (match-string 1))) + ;; Error on unknown posix-class-like syntax + ((rx "[:" (* (any "a-z")) ":]") + (rxt-error "Unknown posix character class `%s'" (match-string 0))) + ;; Error on [= ... ]= collation syntax + ((rx "[" (submatch (any "." "=")) + (* (any "a-z")) (backref 1) "]") + (rxt-error "Unsupported collation syntax `%s'" (match-string 0))) + ;; Other characters stand for themselves + ((rx (or "\n" nonl)) + (string-to-char (match-string 0)))))) + +;; Parse backslash escapes inside PCRE character classes +(defun rxt-parse-char-class-atom/pcre () + (or (rxt-parse-escapes/pcre) + (rxt-token-case + ;; Backslash + digits => octal char + ((rx "\\" (submatch (** 1 3 (any "0-7")))) + (string-to-number (match-string 1) 8)) + ;; Pre-defined character sets + ((rx "\\" (submatch (any "d" "D" "h" "H" "s" "S" "v" "V" "w" "W"))) + (rxt--pcre-char-set (string-to-char (match-string 1)))) + ;; "\b" inside character classes is a backspace + ((rx "\\b") ?\C-h) + ;; Ignore other escapes + ((rx "\\" (submatch nonl)) + (string-to-char (match-string 1)))))) + +;; Look for a range tail (the "-z" in "a-z") after parsing a single +;; character within in a character set. Returns either a character +;; representing the range end, or nil. +(defun rxt-maybe-parse-range-end () + (let ((range-end nil) (end-position nil)) + (when (looking-at (rx "-" (not (any "]")))) + (save-excursion + (forward-char) + (setq range-end (rxt-parse-char-class-atom) + end-position (point)))) + + (if (characterp range-end) + ;; This is a range: move point after it and return the ending character + (progn + (goto-char end-position) + range-end) + ;; Not a range. + nil))) + +;; Return the pre-defined PCRE char-set associated with CHAR: i.e. \d +;; is digits, \D non-digits, \s space characters, etc. +(defun rxt--pcre-char-set (char) + (let* ((base-char (downcase char)) + (negated (/= char base-char)) + (elements (assoc-default base-char rxt-pcre-char-set-alist)) + (base-char-set (apply #'rxt-char-set-union elements))) + (if negated + (rxt-negate base-char-set) + base-char-set))) + + +;;;; Unparser to `rx' syntax + +(defconst rxt-rx-verbose-equivalents + '((bol . line-start) + (eol . line-end) + (nonl . not-newline) + (bos . string-start) + (eos . string-end) + (bow . word-start) + (eow . word-end) + (seq . sequence)) + "Alist of verbose equivalents for short `rx' primitives.") + +(defun rxt-rx-symbol (sym) + (if rxt-verbose-rx-translation + (or (assoc-default sym rxt-rx-verbose-equivalents) + sym) + sym)) + +(defun rxt-adt->rx (re) + (let ((rx + (cl-typecase re + (rxt-primitive + (rxt-rx-symbol (rxt-primitive-rx re))) + + (rxt-string + (if (or (not (rxt-string-case-fold re)) + (string= "" (rxt-string-chars re))) + (rxt-string-chars re) + `(seq + ,@(cl-loop for char across (rxt-string-chars re) + collect `(any ,(upcase char) ,(downcase char)))))) + + (rxt-seq + `(seq ,@(mapcar #'rxt-adt->rx (rxt-seq-elts re)))) + + (rxt-choice + `(or ,@(mapcar #'rxt-adt->rx (rxt-choice-elts re)))) + + (rxt-submatch + (if (rxt-seq-p (rxt-submatch-body re)) + `(submatch + ,@(mapcar #'rxt-adt->rx (rxt-seq-elts (rxt-submatch-body re)))) + `(submatch ,(rxt-adt->rx (rxt-submatch-body re))))) + + (rxt-submatch-numbered + (if (rxt-seq-p (rxt-submatch-numbered-p re)) + `(,(rxt-rx-symbol 'submatch-n) + ,(rxt-submatch-numbered-n re) + ,@(mapcar #'rxt-adt->rx + (rxt-seq-elts + (rxt-submatch-numbered-body re)))) + `(,(rxt-rx-symbol 'submatch-n) + ,(rxt-submatch-numbered-n re) + ,(rxt-adt->rx (rxt-submatch-numbered-body re))))) + + (rxt-backref + (let ((n (rxt-backref-n re))) + (if (<= n 9) + `(backref ,(rxt-backref-n re)) + (rxt-error "Too many backreferences (%s)" n)))) + + (rxt-syntax-class + `(syntax ,(rxt-syntax-class-symbol re))) + + (rxt-char-category + `(category ,(rxt-char-category-symbol re))) + + (rxt-repeat + (let ((from (rxt-repeat-from re)) + (to (rxt-repeat-to re)) + (greedy (rxt-repeat-greedy re)) + (body (rxt-adt->rx (rxt-repeat-body re)))) + (if rxt-verbose-rx-translation + (let ((rx + (cond + ((and (zerop from) (null to)) + `(zero-or-more ,body)) + ((and (equal from 1) (null to)) + `(one-or-more ,body)) + ((and (zerop from) (equal to 1)) + `(zero-or-one ,body)) + ((null to) + `(>= ,from ,body)) + ((equal from to) + `(repeat ,from ,body)) + (t + `(** ,from ,to ,body))))) + (if greedy + (if rxt-explain + rx ; Readable but not strictly accurate. Fixme? + `(maximal-match ,rx)) + `(minimal-match ,rx))) + (cond + ((and (zerop from) (null to)) + `(,(if greedy '* '*?) ,body)) + ((and (equal from 1) (null to)) + `(,(if greedy '+ '+?) ,body)) + ((and (zerop from) (equal to 1)) + `(,(if greedy ? ??) ,body)) + ((null to) + `(>= ,from ,body)) + ((equal from to) + `(= ,from ,body)) + (t + `(** ,from ,to ,body)))))) + + (rxt-char-set-union + (let* ((case-fold (rxt-char-set-union-case-fold re)) + (re (rxt--simplify-char-set re case-fold)) + (chars (rxt-char-set-union-chars re)) + (ranges (rxt-char-set-union-ranges re)) + (classes (rxt-char-set-union-classes re)) + (case-fold (rxt-char-set-union-case-fold re))) + (if (and (null chars) (null ranges) (= 1 (length classes))) + (car classes) + `(any ,@chars ,@ranges ,@classes)))) + + (rxt-char-set-negation + `(not ,(rxt-adt->rx (rxt-char-set-negation-elt re)))) + + (t + (rxt-error "No RX translation of `%s'" (rxt-to-string re)))))) + + ;; Store source information on each fragment of the generated RX + ;; sexp for rxt-explain mode + (when rxt-explain + ;; Use gensyms to store unique source information for multiple + ;; occurrences of primitives like `bol' + (when (symbolp rx) + (setq rx (make-symbol (symbol-name rx)))) + (setf (rxt-location rx) (rxt-location re))) + rx)) + + +;;;; 'Unparser' to PCRE notation + +;;; Based on scsh/posixstr.scm in scsh + +;; To ensure that the operator precedence in the generated regexp does +;; what we want, we need to keep track of what kind of production is +;; returned from each step. Therefore these functions return a string +;; and a numeric "level" which lets the function using the generated +;; regexp know whether it has to be parenthesized: +;; +;; 0: an already parenthesized expression +;; +;; 1: a "piece" binds to any succeeding quantifiers +;; +;; 2: a "branch", or concatenation of pieces, needs parenthesizing to +;; bind to quantifiers +;; +;; 3: a "top", or alternation of branches, needs parenthesizing to +;; bind to quantifiers or to concatenation +;; +;; This idea is stolen straight out of the scsh implementation. + +(defun rxt-adt->pcre (re) + (cl-destructuring-bind (s _) (rxt-adt->pcre/lev re) s)) + +(defun rxt-adt->pcre/lev (re) + (cl-typecase re + (rxt-primitive + (let ((s (rxt-primitive-pcre re))) + (if s + (list s 1) + (rxt-error "No PCRE translation of `%s'" (rxt-to-string re))))) + + (rxt-string (rxt-string->pcre re)) + (rxt-seq (rxt-seq->pcre re)) + (rxt-choice (rxt-choice->pcre re)) + (rxt-submatch (rxt-submatch->pcre re)) + (rxt-backref + (list (format "\\%d" (rxt-backref-n re)) 1)) + (rxt-repeat (rxt-repeat->pcre re)) + + ((or rxt-char-set-union rxt-char-set-negation) + (rxt-char-set->pcre re)) + + ;; FIXME + ;; ((rxt-char-set-intersection re) (rxt-char-set-intersection->pcre re)) + + (t + (rxt-error "No PCRE translation of `%s'" (rxt-to-string re))))) + +(defconst rxt-pcre-metachars (rx (any "\\^.$|()[]*+?{}"))) +(defconst rxt-pcre-charset-metachars (rx (any "]" "[" "\\" "^" "-"))) + +(defun rxt-string->pcre (re) + (let ((chars (rxt-string-chars re))) + (list + (replace-regexp-in-string + rxt-pcre-metachars + "\\\\\\&" chars) + ;; A one-character string is a 'piece' (it binds to a following + ;; quantifier). A longer string is a 'branch' (it has to be + ;; enclosed in parentheses to bind to a following quantifier). + (if (> (length chars) 1) 2 1)))) + +(defun rxt-seq->pcre (re) + (let ((elts (rxt-seq-elts re))) + (if (null elts) + "" + (rxt-seq-elts->pcre elts)))) + +(defun rxt-seq-elts->pcre (elts) + (cl-destructuring-bind + (s lev) (rxt-adt->pcre/lev (car elts)) + (if (null (cdr elts)) + (list s lev) + (cl-destructuring-bind + (s1 lev1) (rxt-seq-elts->pcre (cdr elts)) + (list (concat (rxt-paren-if-necessary s lev) + (rxt-paren-if-necessary s1 lev1)) + 2))))) + +(defun rxt-paren-if-necessary (s lev) + (if (< lev 3) + s + (concat "(?:" s ")"))) + +(defun rxt-choice->pcre (re) + (let ((elts (rxt-choice-elts re))) + (if (null elts) + nil + (rxt-choice-elts->pcre elts)))) + +(defun rxt-choice-elts->pcre (elts) + (cl-destructuring-bind + (s lev) (rxt-adt->pcre/lev (car elts)) + (if (null (cdr elts)) + (list s lev) + (cl-destructuring-bind + (s1 lev1) (rxt-choice-elts->pcre (cdr elts)) + (list (concat s "|" s1) 3))))) + +(defun rxt-submatch->pcre (re) + (cl-destructuring-bind + (s lev) (rxt-adt->pcre/lev (rxt-submatch-body re)) + (list (concat "(" s ")") 0))) + +(defun rxt-repeat->pcre (re) + (let ((from (rxt-repeat-from re)) + (to (rxt-repeat-to re)) + (body (rxt-repeat-body re)) + (greedy (rxt-repeat-greedy re))) + (cl-destructuring-bind + (s lev) (rxt-adt->pcre/lev body) + (cond + ((and to (= from 1) (= to 1)) (list s lev)) + ((and to (= from 0) (= to 0)) (list "" 2)) + (t + (when (> lev 1) ; parenthesize non-atoms + (setq s (concat "(?:" s ")") + lev 0)) + (list (if to + (cond ((and (= from 0) (= to 1)) + (concat s (if greedy "?" "??"))) + ((= from to) + (concat s "{" (number-to-string to) "}")) + (t + (concat s "{" (number-to-string from) + "," (number-to-string to) "}"))) + (cond ((= from 0) + (concat s (if greedy "*" "*?"))) + ((= from 1) + (concat s (if greedy "+" "+?"))) + (t (concat s "{" (number-to-string from) ",}")))) + 1)))))) + +(defun rxt-char-set->pcre (re) + (cond ((rxt-char-set-union-p re) + (list + (concat "[" (rxt-char-set->pcre/chars re) "]") 1)) + + ((rxt-char-set-negation-p re) + (let ((elt (rxt-char-set-negation-elt re))) + (if (rxt-char-set-union-p elt) + (list + (concat "[^" (rxt-char-set->pcre/chars elt) "]") 1) + (rxt-error "No PCRE translation of `%s'" (rxt-to-string elt))))) + + (t + (rxt-error "Non-char-set in rxt-char-set->pcre: %s" re)))) + +;; Fortunately, easier in PCRE than in POSIX! +(defun rxt-char-set->pcre/chars (re) + (cl-flet + ((escape + (char) + (let ((s (char-to-string char))) + (cond ((string-match rxt-pcre-charset-metachars s) + (concat "\\" s)) + + ((and (not (string= s " ")) + (string-match "[^[:graph:]]" s)) + (format "\\x{%x}" char)) + + (t s))))) + + (let ((chars (rxt-char-set-union-chars re)) + (ranges (rxt-char-set-union-ranges re)) + (classes (rxt-char-set-union-classes re))) + + (concat + (mapconcat #'escape chars "") + (mapconcat #'(lambda (rg) + (format "%s-%s" + (escape (car rg)) + (escape (cdr rg)))) + ranges "") + (mapconcat #'(lambda (class) + (format "[:%s:]" class)) + classes ""))))) + + +;;;; Generate all productions of a finite regexp + +(defun rxt-adt->strings (re) + (cl-typecase re + (rxt-primitive + (list "")) + (rxt-string + (list (rxt-string-chars re))) + (rxt-seq + (rxt-seq-elts->strings (rxt-seq-elts re))) + (rxt-choice + (rxt-choice-elts->strings (rxt-choice-elts re))) + (rxt-submatch + (rxt-adt->strings (rxt-submatch-body re))) + (rxt-submatch-numbered + (rxt-adt->strings (rxt-submatch-numbered-body re))) + (rxt-repeat + (rxt-repeat->strings re)) + (rxt-char-set-union + (rxt-char-set->strings re)) + (t + (error "Can't generate productions of %s" + (rxt-syntax-tree-readable re))))) + +(defun rxt-concat-product (heads tails) + (cl-mapcan + (lambda (hs) + (mapcar + (lambda (ts) (concat hs ts)) + tails)) + heads)) + +(defun rxt-seq-elts->strings (elts) + (if (null elts) + '("") + (let ((heads (rxt-adt->strings (car elts))) + (tails (rxt-seq-elts->strings (cdr elts)))) + (rxt-concat-product heads tails)))) + +(defun rxt-choice-elts->strings (elts) + (if (null elts) + '() + (append (rxt-adt->strings (car elts)) + (rxt-choice-elts->strings (cdr elts))))) + +(defun rxt-repeat->strings (re) + (let ((from (rxt-repeat-from re)) + (to (rxt-repeat-to re))) + (if (not to) + (error "Can't generate all productions of unbounded repeat \"%s\"" + (rxt-syntax-tree-readable re)) + (let ((strings (rxt-adt->strings (rxt-repeat-body re)))) + (rxt-repeat-n-m->strings from to strings))))) + +(defun rxt-repeat-n-m->strings (from to strings) + (cond + ((zerop to) '("")) + ((= to from) (rxt-repeat-n->strings from strings)) + (t ; to > from + (let* ((strs-n (rxt-repeat-n->strings from strings)) + (accum (cl-copy-list strs-n))) + (dotimes (i (- to from)) + (setq strs-n (rxt-concat-product strs-n strings)) + (setq accum (nconc accum strs-n))) + accum)))) + +(defun rxt-repeat-n->strings (n strings) + ;; n > 1 + (cond ((zerop n) '("")) + ((= n 1) strings) + (t + (rxt-concat-product + (rxt-repeat-n->strings (- n 1) strings) + strings)))) + +(defun rxt-char-set->strings (re) + (if (rxt-char-set-union-classes re) + (error "Can't generate all productions of named character classes in \"%s\"" + (rxt-syntax-tree-readable re)) + (let ((chars (mapcar #'char-to-string (rxt-char-set-union-chars re)))) + (dolist (range (rxt-char-set-union-ranges re)) + (let ((end (cdr range))) + (cl-do ((i (car range) (+ i 1))) + ((> i end)) + (push (char-to-string i) chars)))) + chars))) + + +;;;; RE-Builder hacks + +(defadvice reb-update-modestring + (after rxt () activate compile) + "This function is hacked for emulated PCRE syntax and regexp conversion." + (setq reb-mode-string + (concat + (format " (%s)" reb-re-syntax) + reb-mode-string)) + (force-mode-line-update)) + +(defadvice reb-change-syntax + (around rxt (&optional syntax) activate compile) + "This function is hacked for emulated PCRE syntax and regexp conversion." + (interactive + (list (intern + (completing-read (format "Select syntax (%s): " reb-re-syntax) + '(read string pcre sregex rx) + nil t "" nil (symbol-name reb-re-syntax))))) + (unless (memq syntax '(read string pcre lisp-re sregex rx)) + (error "Invalid syntax: %s" syntax)) + (let ((re-builder-buffer (get-buffer reb-buffer))) + (setq reb-re-syntax syntax) + (when re-builder-buffer + (with-current-buffer reb-target-buffer + (cl-case syntax + (rx + (let ((rx (rxt-elisp-to-rx reb-regexp))) + (setq reb-regexp-src + (with-temp-buffer + (insert "\n" "'") + (rxt-print rx) + (buffer-string))))) + (pcre + (setq reb-regexp-src (rxt-elisp-to-pcre reb-regexp))))) + (with-current-buffer re-builder-buffer + ;; Hack: prevent reb-auto-update from clobbering the + ;; reb-regexp-src we just set + (let ((inhibit-modification-hooks t)) + (reb-initialize-buffer)) + ;; Enable flag-toggling bindings for PCRE syntax + (rxt--re-builder-switch-pcre-mode))))) + +(defadvice reb-read-regexp + (around rxt () activate compile) + "This function is hacked for emulated PCRE syntax and regexp conversion." + (if (eq reb-re-syntax 'pcre) + (setq ad-return-value + (save-excursion + (goto-char (point-min)) + (rxt-read-delimited-pcre))) + ad-do-it)) + +(defadvice reb-insert-regexp + (around rxt () activate compile) + "This function is hacked for emulated PCRE syntax and regexp conversion." + (if (eq reb-re-syntax 'pcre) + (let ((src (reb-target-binding reb-regexp-src))) + (if src + (insert "\n/" (replace-regexp-in-string "/" "\\/" src t t) "/") + (insert "\n//"))) + ad-do-it)) + +(defadvice reb-cook-regexp + (around rxt (re) activate compile) + "This function is hacked for emulated PCRE syntax and regexp conversion." + (if (eq reb-re-syntax 'pcre) + (setq ad-return-value (rxt-pcre-to-elisp re)) + ad-do-it)) + +(defadvice reb-update-regexp + (around rxt () activate compile) + "This function is hacked for emulated PCRE syntax and regexp conversion." + (setq ad-return-value + (let* ((re-src (reb-read-regexp)) + (re (reb-cook-regexp re-src))) + (with-current-buffer reb-target-buffer + (let ((oldre reb-regexp)) + (prog1 + (not (string= oldre re)) + (setq reb-regexp re) + ;; Update the source re if format requires translation + (when (or (reb-lisp-syntax-p) (eq reb-re-syntax 'pcre)) + (setq reb-regexp-src re-src)))))))) + +(defun rxt--re-builder-switch-pcre-mode () + (rxt--read-pcre-mode + (if (eq reb-re-syntax 'pcre) 1 0))) + +(add-hook 'reb-mode-hook #'rxt--re-builder-switch-pcre-mode) + +(provide 'rxt) +(provide 'pcre2el) + + +;;; pcre2el.el ends here diff --git a/elpa/pcre2el-readme.txt b/elpa/pcre2el-readme.txt new file mode 100644 index 00000000..0ad9a30a --- /dev/null +++ b/elpa/pcre2el-readme.txt @@ -0,0 +1,381 @@ +1 Overview +========== + + `pcre2el' or `rxt' (RegeXp Translator or RegeXp Tools) is a utility + for working with regular expressions in Emacs, based on a + recursive-descent parser for regexp syntax. In addition to converting + (a subset of) PCRE syntax into its Emacs equivalent, it can do the + following: + + - convert Emacs syntax to PCRE + - convert either syntax to `rx', an S-expression based regexp syntax + - untangle complex regexps by showing the parse tree in `rx' form and + highlighting the corresponding chunks of code + - show the complete list of strings (productions) matching a regexp, + provided the list is finite + - provide live font-locking of regexp syntax (so far only for Elisp + buffers -- other modes on the TODO list) + + +2 Usage +======= + + Enable `rxt-mode' or its global equivalent `rxt-global-mode' to get + the default key-bindings. There are three sets of commands: commands + that take a PCRE regexp, commands which take an Emacs regexp, and + commands that try to do the right thing based on the current + mode. Currently, this means Emacs syntax in `emacs-lisp-mode' and + `lisp-interaction-mode', and PCRE syntax everywhere else. + + The default key bindings all begin with `C-c /' and have a mnemonic + structure: `C-c / ', or just `C-c / ' for the + "do what I mean" commands. The complete list of key bindings is given + here and explained in more detail below: + + - "Do-what-I-mean" commands: + `C-c / /': `rxt-explain' + `C-c / c': `rxt-convert-syntax' + `C-c / x': `rxt-convert-to-rx' + `C-c / '': `rxt-convert-to-strings' + + - Commands that work on a PCRE regexp: + `C-c / p e': `rxt-pcre-to-elisp' + `C-c / %': `pcre-query-replace-regexp' + `C-c / p x': `rxt-pcre-to-rx' + `C-c / p '': `rxt-pcre-to-strings' + `C-c / p /': `rxt-explain-pcre' + + - Commands that work on an Emacs regexp: + `C-c / e /': `rxt-explain-elisp' + `C-c / e p': `rxt-elisp-to-pcre' + `C-c / e x': `rxt-elisp-to-rx' + `C-c / e '': `rxt-elisp-to-strings' + `C-c / e t': `rxt-toggle-elisp-rx' + `C-c / t': `rxt-toggle-elisp-rx' + + +2.1 Interactive input and output +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + When used interactively, the conversion commands can read a regexp + either from the current buffer or from the minibuffer. The output is + displayed in the minibuffer and copied to the kill-ring. + + - When called with a prefix argument (`C-u'), they read a regular + expression from the minibuffer literally, without further processing + -- meaning there's no need to double the backslashes if it's an + Emacs regexp. This is the same way commands like + `query-replace-regexp' read input. + + - When the region is active, they use they the region contents, again + literally (without any translation of string syntax). + + - With neither a prefix arg nor an active region, the behavior depends + on whether the command expects an Emacs regexp or a PCRE one. + + Commands that take an Emacs regexp behave like `C-x C-e': they + evaluate the sexp before point (which could be simply a string + literal) and use its value. This is designed for use in Elisp + buffers. As a special case, if point is *inside* a string, it's + first moved to the string end, so in practice they should work as + long as point is somewhere within the regexp literal. + + Commands that take a PCRE regexp try to read a Perl-style delimited + regex literal *after* point in the current buffer, including its + flags. For example, putting point before the `m' in the following + example and doing `C-c / p e' (`rxt-pcre-to-elisp') displays + `\(?:bar\|foo\)', correctly stripping out the whitespace and + comment: + + ,---- + | $x =~ m/ foo | (?# comment) bar /x + `---- + + The PCRE reader currently only works with `/ ... /' delimiters. It + will ignore any preceding `m', `s', or `qr' operator, as well as the + replacement part of an `s' construction. + + Readers for other PCRE-using languages are on the TODO list. + + The translation functions display their result in the minibuffer and + copy it to the kill ring. When translating something into Elisp + syntax, you might need to use the result either literally (e.g. for + interactive input to a command like `query-replace-regexp'), or as a + string to paste into Lisp code. To allow both uses, + `rxt-pcre-to-elisp' copies both versions successively to the + kill-ring. The literal regexp without string quoting is the top + element of the kill-ring, while the Lisp string is the + second-from-top. You can paste the literal regexp somewhere by doing + `C-y', or the Lisp string by `C-y M-y'. + + +2.2 Syntax conversion commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + `rxt-convert-syntax' (`C-c / c') converts between Emacs and PCRE + syntax, depending on the major mode in effect when called. + Alternatively, you can specify the conversion direction explicitly by + using either `rxt-pcre-to-elisp' (`C-c / p e') or `rxt-elisp-to-pcre' + (`C-c / e p'). + + Similarly, `rxt-convert-to-rx' (`C-c / x') converts either kind of + syntax to `rx' form, while `rxt-convert-pcre-to-rx' (`C-c / p x') and + `rxt-convert-elisp-to-rx' (`C-c / e x') convert to `rx' from a + specified source type. + + In Elisp buffers, you can use `rxt-toggle-elisp-rx' (`C-c / t' or `C-c + / e t') to switch the regexp at point back and forth between string + and `rx' syntax. Point should either be within an `rx' or + `rx-to-string' form or a string literal for this to work. + + +2.3 PCRE mode (experimental) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + If you want to use emulated PCRE regexp syntax in all Emacs commands, + try `pcre-mode', which uses Emacs's advice system to make all commands + that read regexps using the minibuffer use emulated PCRE syntax. It + should also work with Isearch. + + This feature is still fairly experimental. It may fail to work or do + the wrong thing with certain commands. Please report bugs. + + `pcre-query-replace-regexp' was originally defined to do query-replace + using emulated PCRE regexps, and is now made somewhat obsolete by + `pcre-mode'. It is bound to `C-c / %' by default, by analogy with + `M-%'. Put the following in your `.emacs' if you want to use + PCRE-style query replacement everywhere: + + ,---- + | (global-set-key [(meta %)] 'pcre-query-replace-regexp) + `---- + +2.5 Explain regexps +~~~~~~~~~~~~~~~~~~~ + + When syntax-highlighting isn't enough to untangle some gnarly regexp + you find in the wild, try the 'explain' commands: `rxt-explain' (`C-c + / /'), `rxt-explain-pcre' (`C-c / p') and `rxt-explain-elisp' (`C-c / + e'). These display the original regexp along with its pretty-printed + `rx' equivalent in a new buffer. Moving point around either in the + original regexp or the `rx' translation highlights corresponding + pieces of syntax, which can aid in seeing things like the scope of + quantifiers. + + I call them "explain" commands because the `rx' form is close to a + plain syntax tree, and this plus the wordiness of the operators + usually helps to clarify what is going on. People who dislike Lisp + syntax might disagree with this assessment. + + +2.6 Generate all matching strings (productions) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Occasionally you come across a regexp which is designed to match a + finite set of strings, e.g. a set of keywords, and it would be useful + to recover the original set. (In Emacs you can generate such regexps + using `regexp-opt'). The commands `rxt-convert-to-strings' (`C-c / + ′'), `rxt-pcre-to-strings' (`C-c / p ′') or `rxt-elisp-to-strings' + (`C-c / e ′') accomplish this by generating all the matching strings + ("productions") of a regexp. (The productions are copied to the kill + ring as a Lisp list). + + An example in Lisp code: + + ,---- + | (regexp-opt '("cat" "caterpillar" "catatonic")) + | ;; => "\\(?:cat\\(?:atonic\\|erpillar\\)?\\)" + | (rxt-elisp-to-strings "\\(?:cat\\(?:atonic\\|erpillar\\)?\\)") + | ;; => '("cat" "caterpillar" "catatonic") + `---- + + For obvious reasons, these commands only work with regexps that don't + include any unbounded quantifiers like `+' or `*'. They also can't + enumerate all the characters that match a named character class like + `[[:alnum:]]'. In either case they will give a (hopefully meaningful) + error message. Due to the nature of permutations, it's still possible + for a finite regexp to generate a huge number of productions, which + will eat memory and slow down your Emacs. Be ready with `C-g' if + necessary. + + +2.7 RE-Builder support +~~~~~~~~~~~~~~~~~~~~~~ + + The Emacs RE-Builder is a useful visual tool which allows using + several different built-in syntaxes via `reb-change-syntax' (`C-c + TAB'). It supports Elisp read and literal syntax and `rx', but it can + only convert from the symbolic forms to Elisp, not the other way. This + package hacks the RE-Builder to also work with emulated PCRE syntax, + and to convert transparently between Elisp, PCRE and rx syntaxes. PCRE + mode reads a delimited Perl-like literal of the form `/ ... /', and it + should correctly support using the `x' and `s' flags. + + +2.8 Use from Lisp +~~~~~~~~~~~~~~~~~ + + Example of using the conversion functions: + ,---- + | (rxt-pcre-to-elisp "(abc|def)\\w+\\d+") + | ;; => "\\(\\(?:abc\\|def\\)\\)[_[:alnum:]]+[[:digit:]]+" + `---- + + All the conversion functions take a single string argument, the regexp + to translate: + + - `rxt-pcre-to-elisp' + - `rxt-pcre-to-rx' + - `rxt-pcre-to-strings' + - `rxt-elisp-to-pcre' + - `rxt-elisp-to-rx' + - `rxt-elisp-to-strings' + + +3 Bugs and Limitations +====================== + +3.1 Limitations on PCRE syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + PCRE has a complicated syntax and semantics, only some of which can be + translated into Elisp. The following subset of PCRE should be + correctly parsed and converted: + + - parenthesis grouping `( .. )', including shy matches `(?: ... )' + - backreferences (various syntaxes), but only up to 9 per expression + - alternation `|' + - greedy and non-greedy quantifiers `*', `*?', `+', `+?', `?' and `??' + (all of which are the same in Elisp as in PCRE) + - numerical quantifiers `{M,N}' + - beginning/end of string `\A', `\Z' + - string quoting `\Q .. \E' + - word boundaries `\b', `\B' (these are the same in Elisp) + - single character escapes `\a', `\c', `\e', `\f', `\n', `\r', `\t', + `\x', and `\octal digits' (but see below about non-ASCII characters) + - character classes `[...]' including Posix escapes + - character classes `\d', `\D', `\h', `\H', `\s', `\S', `\v', `\V' + both within character class brackets and outside + - word and non-word characters `\w' and `\W' (Emacs has the same + syntax, but its meaning is different) + - `s' (single line) and `x' (extended syntax) flags, in regexp + literals, or set within the expression via `(?xs-xs)' or `(?xs-xs: + .... )' syntax + - comments `(?# ... )' + + Most of the more esoteric PCRE features can't really be supported by + simple translation to Elisp regexps. These include the different + lookaround assertions, conditionals, and the "backtracking control + verbs" `(* ...)' . OTOH, there are a few other syntaxes which are + currently unsupported and possibly could be: + + - `\L', `\U', `\l', `\u' case modifiers + - `\g{...}' backreferences + + +3.2 Other limitations +~~~~~~~~~~~~~~~~~~~~~ + + - The order of alternatives and characters in char classes sometimes + gets shifted around, which is annoying. + - Although the string parser tries to interpret PCRE's octal and + hexadecimal escapes correctly, there are problems with matching + 8-bit characters that I don't use enough to properly understand, + e.g.: + ,---- + | (string-match-p (rxt-pcre-to-elisp "\\377") "\377") => nil + `---- + A fix for this would be welcome. + + - Most of PCRE's rules for how `^', `\A', `$' and `\Z' interact with + newlines are not implemented, since they seem less relevant to + Emacs's buffer-oriented rather than line-oriented model. However, + the different meanings of the `.' metacharacter *are* implemented + (it matches newlines with the `/s' flag, but not otherwise). + + - Not currently namespace clean (both `rxt-' and a couple of `pcre-' + functions). + + +3.3 TODO: +~~~~~~~~~ + + - Python-specific extensions to PCRE? + - Language-specific stuff to enable regexp font-locking and explaining + in different modes. Each language would need two functions, which + could be kept in an alist: + + 1. A function to read PCRE regexps, taking the string syntax into + account. E.g., Python has single-quoted, double-quoted and raw + strings, each with different quoting rules. PHP has the kind of + belt-and-suspenders solution you would expect: regexps are in + strings, /and/ you have to include the `/ ... /' delimiters! + Duh. + + 2. A function to copy faces back from the parsed string to the + original buffer text. This has to recognize any escape sequences + so they can be treated as a single character. + + +4 Internal details +================== + + `rxt' defines an internal syntax tree representation of regular + expressions, parsers for Elisp and PCRE syntax, and 'unparsers' + to convert the internal representation to PCRE or `rx' syntax. + Converting from the internal representation to Emacs syntax is + done by converting to `rx' form and passing it to `rx-to-string'. + See `rxt-parse-re', `rxt-adt->pcre', and `rxt-adt->rx' for + details. + + This code is partially based on Olin Shivers' reference SRE + implementation in scsh, although it is simplified in some respects and + extended in others. See `scsh/re.scm', `scsh/spencer.scm' and + `scsh/posixstr.scm' in the `scsh' source tree for details. In + particular, `pcre2el' steals the idea of an abstract data type for + regular expressions and the general structure of the string regexp + parser and unparser. The data types for character sets are extended in + order to support symbolic translation between character set + expressions without assuming a small (Latin1) character set. The + string parser is also extended to parse a bigger variety of + constructions, including POSIX character classes and various Emacs and + Perl regexp assertions. Otherwise, only the bare minimum of scsh's + abstract data type is implemented. + + +5 Soapbox +========= + + Emacs regexps have their annoyances, but it is worth getting used to + them. The Emacs assertions for word boundaries, symbol boundaries, and + syntax classes depending on the syntax of the mode in effect are + especially useful. (PCRE has `\b' for word-boundary, but AFAIK it + doesn't have separate assertions for beginning-of-word and + end-of-word). Other things that might be done with huge regexps in + other languages can be expressed more understandably in Elisp using + combinations of `save-excursion' with the various searches (regexp, + literal, skip-syntax-forward, sexp-movement functions, etc.). + + There's not much point in using `rxt-pcre-to-elisp' to use PCRE + notation in a Lisp program you're going to maintain, since you still + have to double all the backslashes. Better to just use the converted + result (or better yet, the `rx' form). + + +6 History and acknowledgments +============================= + + This was originally created out of an answer to a stackoverflow + question: + [http://stackoverflow.com/questions/9118183/elisp-mechanism-for-converting-pcre-regexps-to-emacs-regexps] + + Thanks to: + + - Wes Hardaker (hardaker) for the initial inspiration and subsequent + hacking + - priyadarshan for requesting RX support + - Daniel Colascione (dcolascione) for a patch to support Emacs's + explicitly-numbered match groups + - Aaron Meurer (asmeurer) for requesting Isearch support + - Philippe Vaucher (silex) for a patch to support `ibuffer-do-replace-regexp' + in PCRE mode diff --git a/elpa/sesman-20190909.1754/sesman-autoloads.el b/elpa/sesman-20190909.1754/sesman-autoloads.el new file mode 100644 index 00000000..8485ba72 --- /dev/null +++ b/elpa/sesman-20190909.1754/sesman-autoloads.el @@ -0,0 +1,98 @@ +;;; sesman-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil "sesman" "sesman.el" (23997 31641 490594 106000)) +;;; Generated autoloads from sesman.el + +(autoload 'sesman-start "sesman" "\ +Start a Sesman session. + +\(fn)" t nil) + +(autoload 'sesman-restart "sesman" "\ +Restart sesman session. +When WHICH is nil, restart the current session; when a single universal +argument or 'linked, restart all linked sessions; when a double universal +argument, t or 'all, restart all sessions. For programmatic use, WHICH can also +be a session or a name of the session, in which case that session is restarted. + +\(fn &optional WHICH)" t nil) + +(autoload 'sesman-quit "sesman" "\ +Terminate a Sesman session. +When WHICH is nil, kill only the current session; when a single universal +argument or 'linked, kill all linked sessions; when a double universal argument, +t or 'all, kill all sessions. For programmatic use, WHICH can also be a session +or a name of the session, in which case that session is killed. + +\(fn &optional WHICH)" t nil) + +(autoload 'sesman-info "sesman" "\ +Display info for all current sessions (`sesman-current-sessions'). +In the resulting minibuffer display linked sessions are numbered and the +other (friendly) sessions are not. When ALL is non-nil, show info for all +sessions. + +\(fn &optional ALL)" t nil) + +(autoload 'sesman-link-with-buffer "sesman" "\ +Ask for SESSION and link with BUFFER. +BUFFER defaults to current buffer. On universal argument, or if BUFFER is 'ask, +ask for buffer. + +\(fn &optional BUFFER SESSION)" t nil) + +(autoload 'sesman-link-with-directory "sesman" "\ +Ask for SESSION and link with DIR. +DIR defaults to `default-directory'. On universal argument, or if DIR is 'ask, +ask for directory. + +\(fn &optional DIR SESSION)" t nil) + +(autoload 'sesman-link-with-project "sesman" "\ +Ask for SESSION and link with PROJECT. +PROJECT defaults to current project. On universal argument, or if PROJECT is +'ask, ask for the project. SESSION defaults to the current session. + +\(fn &optional PROJECT SESSION)" t nil) + +(autoload 'sesman-link-with-least-specific "sesman" "\ +Ask for SESSION and link with the least specific context available. +Normally the least specific context is the project. If not in a project, link +with the `default-directory'. If `default-directory' is nil, link with current +buffer. + +\(fn &optional SESSION)" t nil) + +(autoload 'sesman-unlink "sesman" "\ +Break any of the previously created links. + +\(fn)" t nil) + (autoload 'sesman-map "sesman" "Session management prefix keymap." t 'keymap) + +;;;*** + +;;;### (autoloads nil "sesman-browser" "sesman-browser.el" (23997 +;;;;;; 31641 489204 100000)) +;;; Generated autoloads from sesman-browser.el + +(autoload 'sesman-browser "sesman-browser" "\ +Display an interactive session browser. +See `sesman-browser-mode' for more details. + +\(fn)" t nil) + +;;;*** + +;;;### (autoloads nil nil ("sesman-pkg.el") (23997 31641 487487 99000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; sesman-autoloads.el ends here diff --git a/elpa/sesman-20190909.1754/sesman-browser.el b/elpa/sesman-20190909.1754/sesman-browser.el new file mode 100644 index 00000000..6f6c8cc5 --- /dev/null +++ b/elpa/sesman-20190909.1754/sesman-browser.el @@ -0,0 +1,482 @@ +;;; sesman-browser.el --- Interactive Browser for Sesman -*- lexical-binding: t -*- +;; +;; Copyright (C) 2018, Vitalie Spinu +;; Author: Vitalie Spinu +;; URL: https://github.com/vspinu/sesman +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This file is *NOT* part of GNU Emacs. +;; +;; This program 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, or +;; (at your option) any later version. +;; +;; This program 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Interactive session browser. +;; +;;; Code: + +(require 'seq) +(require 'sesman) + +(defgroup sesman-browser nil + "Browser for Sesman." + :prefix "sesman-browser-" + :group 'sesman + :link '(url-link :tag "GitHub" "https://github.com/vspinu/sesman")) + +(defface sesman-browser-highligh-face + '((default (:inherit highlight :weight bold))) + "Face used to highlight currently selected button." + :group 'sesman-browser) + +(defface sesman-browser-button-face + '((default (:inherit button :slant italic))) + "Face used to highlight currently selected object." + :group 'sesman-browser) + +(defvar-local sesman-browser--sort-types '(name relevance)) +(defcustom sesman-browser-sort-type 'name + "Default sorting type in sesman browser buffers. +Currently can be either 'name or 'relevance." + :type '(choice (const name) (const relevance)) + :group 'sesman-browser) + +(defvar sesman-browser-map + (let (sesman-browser-map) + (define-prefix-command 'sesman-browser-map) + (define-key sesman-browser-map (kbd "r") #'sesman-browser-restart-session) + (define-key sesman-browser-map (kbd "q") #'sesman-browser-quit-session) + (define-key sesman-browser-map (kbd "b") #'sesman-browser-link-with-buffer) + (define-key sesman-browser-map (kbd "d") #'sesman-browser-link-with-directory) + (define-key sesman-browser-map (kbd "p") #'sesman-browser-link-with-project) + (define-key sesman-browser-map (kbd "u") #'sesman-browser-unlink) + sesman-browser-map) + "Prefix keymap for sesman commands from sesman browser.") + +(defvar sesman-browser-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "n") #'sesman-browser-vertical-next) + (define-key map (kbd "p") #'sesman-browser-vertical-prev) + (define-key map (kbd "f") #'sesman-browser-forward) + (define-key map (kbd "b") #'sesman-browser-backward) + (define-key map [remap forward-paragraph] #'sesman-browser-session-next) + (define-key map [remap backward-paragraph] #'sesman-browser-session-prev) + (define-key map (kbd "C-M-n") #'sesman-browser-session-next) + (define-key map (kbd "C-M-p") #'sesman-browser-session-prev) + (define-key map (kbd "") #'sesman-browser-forward) + (define-key map (kbd "") #'sesman-browser-backward) + (define-key map (kbd "") #'sesman-goto) + (define-key map (kbd "o") #'sesman-show) + (define-key map (kbd "t") #'sesman-browser-toggle-sort) + (define-key map (kbd "S") #'sesman-browser-toggle-sort) + (define-key map (kbd "l b") #'sesman-browser-link-with-buffer) + (define-key map (kbd "l d") #'sesman-browser-link-with-directory) + (define-key map (kbd "l p") #'sesman-browser-link-with-project) + (define-key map (kbd "u") #'sesman-browser-unlink) + (define-key map (kbd "s") 'sesman-browser-map) + (define-key map (kbd "C-c C-s") 'sesman-browser-map) + (easy-menu-define sesman-browser-mode-map map + "Sesman Browser" + '("SesmanBrowser" + ["Next row" sesman-browser-vertical-next] + ["Previous row" sesman-browser-vertical-prev] + ["Next button" sesman-browser-forward] + ["Previous button" sesman-browser-backward] + ["Next session" sesman-browser-session-next] + ["Previous session" sesman-browser-session-prev] + "--" + ["Goto buffer" sesman-goto] + ["Show buffer" sesman-show] + "--" + ["Link with Buffer" sesman-browser-link-with-buffer] + ["Link with Directory" sesman-browser-link-with-directory] + ["Link with Project" sesman-browser-link-with-project] + ["Unlink" sesman-browser-unlink] + "--" + ["Toggle sort" sesman-browser-toggle-sort] + ["Refresh View" revert-buffer])) + map) + "Local keymap in `sesman-browser-mode'.") + + +;;; Utilities + +(defun sesman-browser--closeby-pos (prop lax) + (or (when (get-text-property (point) prop) + (point)) + (when (and (not (bobp)) + (get-text-property (1- (point)) prop)) + (1- (point))) + (when lax + (let ((next (save-excursion + (and + (goto-char (next-single-char-property-change (point) prop)) + (get-text-property (point) prop) + (point)))) + (prev (save-excursion + (and + (goto-char (previous-single-char-property-change (point) prop)) + (not (bobp)) + (get-text-property (1- (point)) prop) + (1- (point)))))) + (if next + (if prev + (if (< (- (point) prev) (- next (point))) + prev + next) + next) + prev))))) + +(defun sesman-browser--closeby-value (prop lax) + (when-let ((pos (sesman-browser--closeby-pos prop lax))) + (get-text-property pos prop))) + +(defun sesman-browser-get (what &optional no-error lax) + "Get value of the property WHAT at point. +If NO-ERROR is non-nil, don't throw an error if no value has been found and +return nil. If LAX is non-nil, search nearby and return the closest value." + (when (derived-mode-p 'sesman-browser-mode) + (or (let ((prop (pcase what + ('session :sesman-session) + ('link :sesman-link) + ('object :sesman-object) + (_ what)))) + (sesman-browser--closeby-value prop 'lax)) + (unless no-error + (user-error "No %s %s" what (if lax "nearby" "at point")))))) + + +;;; Navigation + +(defvar-local sesman-browser--section-overlay nil) +(defvar-local sesman-browser--stop-overlay nil) + +(when (fboundp 'define-fringe-bitmap) + (define-fringe-bitmap 'sesman-left-bar + [#b00001100] nil nil '(top t))) + +(defun sesman-browser--next (prop) + (let ((pos (point))) + (goto-char (previous-single-char-property-change (point) prop)) + (unless (get-text-property (point) prop) + (goto-char (previous-single-char-property-change (point) prop))) + (when (bobp) + (goto-char pos)))) + +(defun sesman-browser--prev (prop) + (let ((pos (point))) + (goto-char (next-single-char-property-change (point) prop)) + (unless (get-text-property (point) prop) + (goto-char (next-single-char-property-change (point) prop))) + (when (eobp) + (goto-char pos)))) + +(defun sesman-browser-forward () + "Go to next button." + (interactive) + (sesman-browser--prev :sesman-stop)) + +(defun sesman-browser-backward () + "Go to previous button." + (interactive) + (sesman-browser--next :sesman-stop)) + +(defun sesman-browser-vertical-next () + "Go to next button section or row." + (interactive) + (sesman-browser--prev :sesman-vertical-stop)) + +(defun sesman-browser-vertical-prev () + "Go to previous button section or row." + (interactive) + (sesman-browser--next :sesman-vertical-stop)) + +(defun sesman-browser-session-next () + "Go to next session." + (interactive) + (sesman-browser--prev :sesman-session-stop)) + +(defun sesman-browser-session-prev () + "Go to previous session." + (interactive) + (sesman-browser--next :sesman-session-stop)) + + +;;; Display + +(defun sesman-goto (&optional no-switch) + "Go to most relevant buffer for session at point. +If NO-SWITCH is non-nil, only display the buffer." + (interactive "P") + (let ((object (get-text-property (point) :sesman-object))) + (if (and object (bufferp object)) + (if no-switch + (display-buffer object) + (pop-to-buffer object)) + (let* ((session (sesman-browser-get 'session)) + (info (sesman-session-info (sesman--system) session)) + (buffers (or (plist-get info :buffers) + (let ((objects (plist-get info :objects))) + (seq-filter #'bufferp objects))))) + (if buffers + (let ((most-recent-buf (seq-find (lambda (b) + (member b buffers)) + (buffer-list)))) + (if no-switch + (display-buffer most-recent-buf) + (pop-to-buffer most-recent-buf))) + (user-error "Cannot jump to session %s; it doesn't contain any buffers" (car session))))))) + +(defun sesman-show () + "Show the most relevant buffer for the session at point." + (interactive) + (sesman-goto 'no-switch)) + +(defun sesman-browser--sensor-function (&rest _ignore) + (let ((beg (or (when (get-text-property (point) :sesman-stop) + (if (get-text-property (1- (point)) :sesman-stop) + (previous-single-char-property-change (point) :sesman-stop) + (point))) + (next-single-char-property-change (point) :sesman-stop))) + (end (next-single-char-property-change (point) :sesman-stop))) + (move-overlay sesman-browser--stop-overlay beg end) + (when window-system + (let ((beg (get-text-property (point) :sesman-fragment-beg)) + (end (get-text-property (point) :sesman-fragment-end))) + (when (and beg end) + (move-overlay sesman-browser--section-overlay beg end)))))) + + +;;; Sesman UI + +(defun sesman-browser-quit-session () + "Quite session at point." + (interactive) + (sesman-quit (sesman-browser-get 'session))) + +(defun sesman-browser-restart-session () + "Restart session at point." + (interactive) + (sesman-restart (sesman-browser-get 'session))) + +(defun sesman-browser-link-with-buffer () + "Ask for buffer to link session at point to." + (interactive) + (let ((session (sesman-browser-get 'session))) + (sesman-link-with-buffer 'ask session))) + +(defun sesman-browser-link-with-directory () + "Ask for directory to link session at point to." + (interactive) + (let ((session (sesman-browser-get 'session))) + (sesman-link-with-directory 'ask session))) + +(defun sesman-browser-link-with-project () + "Ask for project to link session at point to." + (interactive) + (let ((session (sesman-browser-get 'session))) + (sesman-link-with-project 'ask session))) + +(defun sesman-browser-unlink () + "Unlink the link at point or ask for link to unlink." + (interactive) + (if-let ((link (sesman-browser-get 'link 'no-error))) + (sesman--unlink link) + (if-let ((links (sesman-links (sesman--system) + (sesman-browser-get 'session)))) + (mapc #'sesman--unlink + (sesman--ask-for-link "Unlink: " links 'ask-all)) + (user-error "No links for session %s" (car (sesman-browser-get 'session))))) + (run-hooks 'sesman-post-command-hook)) + + +;;; Major Mode + +(defun sesman-browser-revert (&rest _ignore) + "Refresh current browser buffer." + (let ((pos (point))) + (sesman-browser) + ;; simple but not particularly reliable or useful + (goto-char (min pos (point-max))))) + +(defun sesman-browser-revert-all (system) + "Refresh all Sesman SYSTEM browsers." + (mapc (lambda (b) + (with-current-buffer b + (when (and (derived-mode-p 'sesman-browser-mode) + (eq system (sesman--system))) + (sesman-browser-revert)))) + (buffer-list))) + +(defun sesman-browser--goto-stop (stop-value) + (let ((search t)) + (goto-char (point-min)) + (while search + (goto-char (next-single-char-property-change (point) :sesman-stop)) + (if (eobp) + (progn (setq search nil) + (goto-char (next-single-char-property-change (point-min) :sesman-stop))) + (when (equal (get-text-property (point) :sesman-stop) stop-value) + (setq search nil)))))) + +(defun sesman-browser-toggle-sort () + "Toggle sorting of sessions. +See `sesman-browser-sort-type' for the default sorting type." + (interactive) + (when (eq sesman-browser-sort-type + (car sesman-browser--sort-types)) + (pop sesman-browser--sort-types)) + (unless sesman-browser--sort-types + (setq-local sesman-browser--sort-types (default-value 'sesman-browser--sort-types))) + (setq sesman-browser-sort-type (pop sesman-browser--sort-types)) + (let ((stop (sesman-browser-get :sesman-stop nil 'lax))) + (sesman-browser) + (sesman-browser--goto-stop stop) + (sesman-browser--sensor-function)) + (message "Sorted by %s" + (propertize (symbol-name sesman-browser-sort-type) 'face 'bold))) + +(define-derived-mode sesman-browser-mode special-mode "SesmanBrowser" + "Interactive view of Sesman sessions. +When applicable, system specific commands are locally bound to j when point is +on a session object." + ;; ensure there is a sesman-system here + (sesman--system) + (delete-all-overlays) + (setq-local sesman-browser--stop-overlay (make-overlay (point) (point))) + (overlay-put sesman-browser--stop-overlay 'face 'sesman-browser-highligh-face) + (setq-local sesman-browser--section-overlay (make-overlay (point) (point))) + (when window-system + (let* ((fringe-spec '(left-fringe sesman-left-bar sesman-browser-highligh-face)) + (dummy-string (propertize "|" 'display fringe-spec))) + (overlay-put sesman-browser--section-overlay 'line-prefix dummy-string))) + (add-hook 'sesman-post-command-hook 'sesman-browser-revert nil t) + (setq-local display-buffer-base-action '(nil . ((inhibit-same-window . t)))) + (setq-local sesman-browser--sort-types (default-value 'sesman-browser--sort-types)) + (setq-local revert-buffer-function #'sesman-browser-revert)) + +(defun sesman-browser--insert-session (system ses i) + (let ((ses-name (car ses)) + (head-template "%17s") + beg end) + (setq beg (point)) + + ;; session header + (insert (format "%3d: " i)) + (insert (propertize (car ses) + :sesman-stop ses-name + :sesman-vertical-stop t + :sesman-session-stop t + 'face 'bold + 'cursor-sensor-functions (list #'sesman-browser--sensor-function) + 'mouse-face 'highlight) + "\n") + + ;; links + (insert (format head-template "linked-to: ")) + (let ((link-groups (sesman-grouped-links system ses)) + (vert-stop)) + (dolist (grp link-groups) + (let* ((type (car grp))) + (dolist (link (cdr grp)) + (when (> (current-column) fill-column) + (insert "\n" (format head-template " ")) + (setq vert-stop nil)) + (let ((val (sesman--abbrev-path-maybe (sesman--lnk-value link)))) + (insert (propertize (sesman--format-context type val 'sesman-browser-button-face) + :sesman-stop (car link) + :sesman-vertical-stop (unless vert-stop (setq vert-stop t)) + :sesman-link link + 'cursor-sensor-functions (list #'sesman-browser--sensor-function) + 'mouse-face 'highlight))) + (insert " "))))) + (insert "\n") + + ;; objects + (insert (format head-template "objects: ")) + (let* ((info (sesman-session-info system ses)) + (map (plist-get info :map)) + (objects (plist-get info :objects)) + (strings (or (plist-get info :strings) + (mapcar (lambda (x) (format "%s" x)) objects))) + (kvals (seq-mapn #'cons objects strings)) + (kvals (seq-sort (lambda (a b) (string-lessp (cdr a) (cdr b))) + kvals)) + (vert-stop)) + (dolist (kv kvals) + (when (> (current-column) fill-column) + (insert "\n" (format head-template " ")) + (setq vert-stop nil)) + (let ((str (replace-regexp-in-string ses-name "%s" (cdr kv) nil t))) + (insert (propertize str + :sesman-stop str + :sesman-vertical-stop (unless vert-stop (setq vert-stop t)) + :sesman-object (car kv) + 'cursor-sensor-functions (list #'sesman-browser--sensor-function) + 'face 'sesman-browser-button-face + 'mouse-face 'highlight + 'help-echo "mouse-2: visit in other window" + 'keymap map) + " ")))) + + ;; session properties + (setq end (point)) + (put-text-property beg end :sesman-session ses) + (put-text-property beg end :sesman-session-name ses-name) + (put-text-property beg end :sesman-fragment-beg beg) + (put-text-property beg end :sesman-fragment-end end) + (insert "\n\n"))) + +;;;###autoload +(defun sesman-browser () + "Display an interactive session browser. +See `sesman-browser-mode' for more details." + (interactive) + (let* ((system (sesman--system)) + (pop-to (called-interactively-p 'any)) + (sessions (sesman-sessions system)) + (cur-session (when pop-to + (sesman-current-session 'CIDER))) + (buff (get-buffer-create (format "*sesman %s browser*" system)))) + (with-current-buffer buff + (setq-local sesman-system system) + (sesman-browser-mode) + (cursor-sensor-mode 1) + (let ((inhibit-read-only t) + (sessions (pcase sesman-browser-sort-type + ('name (seq-sort (lambda (a b) (string-greaterp (car b) (car a))) + sessions)) + ('relevance (sesman--sort-sessions system sessions)) + (_ (error "Invalid `sesman-browser-sort-type'")))) + (i 0)) + (erase-buffer) + (insert "\n ") + (insert (propertize (format "%s Sessions:" system) + 'face '(bold font-lock-keyword-face))) + (insert "\n\n") + (dolist (ses sessions) + (setq i (1+ i)) + (sesman-browser--insert-session system ses i)) + (when pop-to + (pop-to-buffer buff) + (sesman-browser--goto-stop (car cur-session))) + (sesman-browser--sensor-function))))) + +(provide 'sesman-browser) +;;; sesman-browser.el ends here diff --git a/elpa/sesman-20190909.1754/sesman-pkg.el b/elpa/sesman-20190909.1754/sesman-pkg.el new file mode 100644 index 00000000..5f896f3f --- /dev/null +++ b/elpa/sesman-20190909.1754/sesman-pkg.el @@ -0,0 +1,12 @@ +(define-package "sesman" "20190909.1754" "Generic Session Manager" + '((emacs "25")) + :keywords + '("process") + :authors + '(("Vitalie Spinu")) + :maintainer + '("Vitalie Spinu") + :url "https://github.com/vspinu/sesman") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/sesman-20190909.1754/sesman.el b/elpa/sesman-20190909.1754/sesman.el new file mode 100644 index 00000000..e0a16b37 --- /dev/null +++ b/elpa/sesman-20190909.1754/sesman.el @@ -0,0 +1,1003 @@ +;;; sesman.el --- Generic Session Manager -*- lexical-binding: t -*- +;; +;; Copyright (C) 2018, Vitalie Spinu +;; Author: Vitalie Spinu +;; URL: https://github.com/vspinu/sesman +;; Keywords: process +;; Version: 0.3.3-DEV +;; Package-Requires: ((emacs "25")) +;; Keywords: processes, tools, vc +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This file is *NOT* part of GNU Emacs. +;; +;; This program 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, or +;; (at your option) any later version. +;; +;; This program 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Sesman provides facilities for session management and interactive session +;; association with the current contexts (project, directory, buffers etc). See +;; project's readme for more details. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(require 'cl-generic) +(require 'seq) +(require 'subr-x) +(require 'vc) + +(defgroup sesman nil + "Generic Session Manager." + :prefix "sesman-" + :group 'tools + :link '(url-link :tag "GitHub" "https://github.com/vspinu/sesman")) + +(defface sesman-project-face + '((default (:inherit font-lock-doc-face))) + "Face used to mark projects." + :group 'sesman) + +(defface sesman-directory-face + '((default (:inherit font-lock-type-face))) + "Face used to mark directories." + :group 'sesman) + +(defface sesman-buffer-face + '((default (:inherit font-lock-preprocessor-face))) + "Face used to mark buffers." + :group 'sesman) + +(defcustom sesman-use-friendly-sessions t + "If non-nil consider friendly sessions when looking for current sessions. +The definition of friendly sessions is system dependent but usually means +sessions running in dependent projects." + :group 'sesman + :type 'boolean + :package-version '(sesman . "0.3.2")) + +(defcustom sesman-follow-symlinks 'vc + "When non-nil, follow symlinks during the file expansion. +When nil, don't follow symlinks. When 'vc, follow symlinks only when +`vc-follow-symlinks' is non-nil. When t, always follow symlinks." + :group 'sesman + :type '(choice (const :tag "Comply with `vc-follow-symlinks'" vc) + (const :tag "Don't follow symlinks" nil) + (const :tag "Follow symlinks" t)) + :package-version '(sesman . "0.3.3")) +(put 'sesman-follow-symlinks 'safe-local-variable (lambda (x) (memq x '(vc nil t)))) + +;; (defcustom sesman-disambiguate-by-relevance t +;; "If t choose most relevant session in ambiguous situations, otherwise ask. +;; Ambiguity arises when multiple sessions are associated with current context. By +;; default only projects could be associated with multiple sessions. See +;; `sesman-single-link-contexts' in order to change that. Relevance is decided by +;; system's implementation, see `sesman-more-relevant-p'." +;; :group 'sesman +;; :type 'boolean) + +(defcustom sesman-single-link-context-types '(buffer) + "List of context types to which at most one session can be linked." + :group 'sesman + :type '(repeat symbol) + :package-version '(sesman . "0.1.0")) + +;; FIXME: +;; (defcustom sesman-abbreviate-paths 2 +;; "Abbreviate paths to that many parents. +;; When set to nil, don't abbreviate directories." +;; :group 'sesman +;; :type '(choice number +;; (const :tag "Don't abbreviate" nil))) + +(defvar sesman-sessions-hashmap (make-hash-table :test #'equal) + "Hash-table of all sesman sessions. +Key is a cons (system-name . session-name).") + +(defvar sesman-links-alist nil + "An alist of all sesman links. +Each element is of the form (key cxt-type cxt-value) where +\"key\" is of the form (system-name . session-name). system-name +and cxt-type must be symbols.") + +(defvar-local sesman-system nil + "Name of the system managed by `sesman'. +Can be either a symbol, or a function returning a symbol.") +(put 'sesman-system 'permanent-local 't) + + + +;; Internal Utilities + +(defun sesman--on-C-u-u-sessions (system which) + (cond + ((null which) + (let ((ses (sesman-current-session system))) + (when ses + (list ses)))) + ((or (equal which '(4)) (eq which 'linked)) + (sesman--linked-sessions system 'sort)) + ((or (equal which '(16)) (eq which 'all) (eq which t)) + (sesman--all-system-sessions system 'sort)) + ;; session itself + ((and (listp which) + (or (stringp (car which)) + (symbolp (car which)))) + (list which)) + ;; session name + ((or (stringp which) + (symbolp which) + (gethash (cons system which) sesman-sessions-hashmap))) + (t (error "Invalid which argument (%s)" which)))) + +(defun sesman--cap-system-name (system) + (let ((name (symbol-name system))) + (if (string-match-p "^[[:upper:]]" name) + name + (capitalize name)))) + +(defun sesman--least-specific-context (system) + (seq-some (lambda (ctype) + (when-let (val (sesman-context ctype system)) + (cons ctype val))) + (reverse (sesman-context-types system)))) + +(defun sesman--link-session-interactively (session cxt-type cxt-val) + (let ((system (sesman--system))) + (unless cxt-type + (let ((cxt (sesman--least-specific-context system))) + (setq cxt-type (car cxt) + cxt-val (cdr cxt)))) + (let ((cxt-name (symbol-name cxt-type))) + (if (member cxt-type (sesman-context-types system)) + (let ((session (or session + (sesman-ask-for-session + system + (format "Link with %s %s: " + cxt-name (sesman--abbrev-path-maybe + (sesman-context cxt-type system))) + (sesman--all-system-sessions system 'sort) + 'ask-new)))) + (sesman-link-session system session cxt-type cxt-val)) + (error (format "%s association not allowed for this system (%s)" + (capitalize cxt-name) + system)))))) + +;; FIXME: incorporate `sesman-abbreviate-paths' +(defun sesman--abbrev-path-maybe (obj) + (if (stringp obj) + (abbreviate-file-name obj) + obj)) + +(defun sesman--system-in-buffer (&optional buffer) + (with-current-buffer (or buffer (current-buffer)) + (if (functionp sesman-system) + (funcall sesman-system) + sesman-system))) + +(defun sesman--system () + (if sesman-system + (if (functionp sesman-system) + (funcall sesman-system) + sesman-system) + (error "No `sesman-system' in buffer `%s'" (current-buffer)))) + +(defun sesman--linked-sessions (system &optional sort cxt-types) + (let* ((system (or system (sesman--system))) + (cxt-types (or cxt-types (sesman-context-types system)))) + ;; just in case some links are lingering due to user errors + (sesman--clear-links) + (delete-dups + (mapcar (lambda (assoc) + (gethash (car assoc) sesman-sessions-hashmap)) + (sesman-current-links system nil sort cxt-types))))) + +(defun sesman--friendly-sessions (system &optional sort) + (let ((sessions (seq-filter (lambda (ses) (sesman-friendly-session-p system ses)) + (sesman--all-system-sessions system)))) + (if sort + (sesman--sort-sessions system sessions) + sessions))) + +(defun sesman--all-system-sessions (&optional system sort) + "Return a list of sessions registered with SYSTEM. +If SORT is non-nil, sort in relevance order." + (let ((system (or system (sesman--system))) + sessions) + (maphash + (lambda (k s) + (when (eql (car k) system) + (push s sessions))) + sesman-sessions-hashmap) + (if sort + (sesman--sort-sessions system sessions) + sessions))) + +;; FIXME: make this a macro +(defun sesman--link-lookup-fn (&optional system ses-name cxt-type cxt-val x) + (let ((system (or system (caar x))) + (ses-name (or ses-name (cdar x))) + (cxt-type (or cxt-type (nth 1 x))) + (cxt-val (or cxt-val (nth 2 x)))) + (lambda (el) + (and (or (null system) (eq (caar el) system)) + (or (null ses-name) (equal (cdar el) ses-name)) + (or (null cxt-type) + (if (listp cxt-type) + (member (nth 1 el) cxt-type) + (eq (nth 1 el) cxt-type))) + (or (null cxt-val) (equal (nth 2 el) cxt-val)))))) + +(defun sesman--unlink (x) + (setq sesman-links-alist + (seq-remove (sesman--link-lookup-fn nil nil nil nil x) + sesman-links-alist))) + +(defun sesman--clear-links () + (setq sesman-links-alist + (seq-filter (lambda (x) + (gethash (car x) sesman-sessions-hashmap)) + sesman-links-alist))) + +(defun sesman--format-session-objects (system session &optional sep) + (let ((info (sesman-session-info system session))) + (if (and (listp info) + (keywordp (car info))) + (let ((ses-name (car session)) + (sep (or sep " ")) + (strings (or (plist-get info :strings) + (mapcar (lambda (x) (format "%s" x)) + (plist-get info :objects))))) + (mapconcat (lambda (str) + (replace-regexp-in-string ses-name "..." str nil t)) + strings sep)) + (format "%s" info)))) + +(defun sesman--format-session (system ses &optional prefix) + (format (propertize "%s%s [%s] linked-to %s" 'face 'bold) + (or prefix "") + (propertize (car ses) 'face 'bold) + (propertize (sesman--format-session-objects system ses ", ") 'face 'italic) + (sesman-grouped-links system ses t t))) + +(defun sesman--format-link (link) + (let* ((system (sesman--lnk-system-name link)) + (session (gethash (car link) sesman-sessions-hashmap))) + (format "%s(%s) -> %s [%s]" + (sesman--lnk-context-type link) + (propertize (format "%s" (sesman--abbrev-path-maybe (sesman--lnk-value link))) + 'face 'bold) + (propertize (sesman--lnk-session-name link) 'face 'bold) + (if session + (sesman--format-session-objects system session) + "invalid")))) + +(defun sesman--ask-for-link (prompt links &optional ask-all) + (let* ((name.keys (mapcar (lambda (link) + (cons (sesman--format-link link) link)) + links)) + (name.keys (append name.keys + (when (and ask-all (> (length name.keys) 1)) + '(("*all*"))))) + (nms (mapcar #'car name.keys)) + (sel (completing-read prompt nms nil t nil nil (car nms)))) + (cond ((string= sel "*all*") + links) + (ask-all + (list (cdr (assoc sel name.keys)))) + (t + (cdr (assoc sel name.keys)))))) + +(defun sesman--sort-sessions (system sessions) + (seq-sort (lambda (x1 x2) + (sesman-more-relevant-p system x1 x2)) + sessions)) + +(defun sesman--sort-links (system links) + (seq-sort (lambda (x1 x2) + (sesman-more-relevant-p system + (gethash (car x1) sesman-sessions-hashmap) + (gethash (car x2) sesman-sessions-hashmap))) + links)) + +;; link data structure accessors +(defun sesman--lnk-system-name (lnk) + (caar lnk)) +(defun sesman--lnk-session-name (lnk) + (cdar lnk)) +(defun sesman--lnk-context-type (lnk) + (cadr lnk)) +(defun sesman--lnk-value (lnk) + (nth 2 lnk)) + + +;;; User Interface + +(defun sesman-post-command-hook nil + "Normal hook ran after every state-changing Sesman command.") + +;;;###autoload +(defun sesman-start () + "Start a Sesman session." + (interactive) + (let ((system (sesman--system))) + (message "Starting new %s session ..." system) + (prog1 (sesman-start-session system) + (run-hooks 'sesman-post-command-hook)))) + +;;;###autoload +(defun sesman-restart (&optional which) + "Restart sesman session. +When WHICH is nil, restart the current session; when a single universal +argument or 'linked, restart all linked sessions; when a double universal +argument, t or 'all, restart all sessions. For programmatic use, WHICH can also +be a session or a name of the session, in which case that session is restarted." + (interactive "P") + (let* ((system (sesman--system)) + (sessions (sesman--on-C-u-u-sessions system which))) + (if (null sessions) + (message "No %s sessions found" system) + (with-temp-message (format "Restarting %s %s %s" system + (if (= 1 (length sessions)) "session" "sessions") + (mapcar #'car sessions)) + (mapc (lambda (s) + (sesman-restart-session system s)) + sessions)) + ;; restarting is not guaranteed to finish here, but what can we do? + (run-hooks 'sesman-post-command-hook)))) + +;;;###autoload +(defun sesman-quit (&optional which) + "Terminate a Sesman session. +When WHICH is nil, kill only the current session; when a single universal +argument or 'linked, kill all linked sessions; when a double universal argument, +t or 'all, kill all sessions. For programmatic use, WHICH can also be a session +or a name of the session, in which case that session is killed." + (interactive "P") + (let* ((system (sesman--system)) + (sessions (sesman--on-C-u-u-sessions system which))) + (if (null sessions) + (message "No %s sessions found" system) + (with-temp-message (format "Killing %s %s %s" system + (if (= 1 (length sessions)) "session" "sessions") + (mapcar #'car sessions)) + (mapc (lambda (s) + (sesman-unregister system s) + (sesman-quit-session system s)) + sessions)) + (run-hooks 'sesman-post-command-hook)))) + +;;;###autoload +(defun sesman-info (&optional all) + "Display info for all current sessions (`sesman-current-sessions'). +In the resulting minibuffer display linked sessions are numbered and the +other (friendly) sessions are not. When ALL is non-nil, show info for all +sessions." + (interactive "P") + (let* ((system (sesman--system)) + (i 1) + (sessions (if all + (sesman-sessions system t) + (sesman-current-sessions system))) + (empty-prefix (if (> (length sessions) 1) " " ""))) + (if sessions + (message (mapconcat (lambda (ses) + (let ((prefix (if (sesman-relevant-session-p system ses) + (prog1 (format "%d " i) + (setq i (1+ i))) + empty-prefix))) + (sesman--format-session system ses prefix))) + sessions + "\n")) + (message "No %s%s sessions" + (if all "" "current ") + system)))) + +;;;###autoload +(defun sesman-link-with-buffer (&optional buffer session) + "Ask for SESSION and link with BUFFER. +BUFFER defaults to current buffer. On universal argument, or if BUFFER is 'ask, +ask for buffer." + (interactive "P") + (let ((buf (if (or (eq buffer 'ask) + (equal buffer '(4))) + (let ((this-system (sesman--system))) + (read-buffer "Link buffer: " (current-buffer) t + (lambda (buf-cons) + (equal this-system + (sesman--system-in-buffer (cdr buf-cons)))))) + (or buffer (current-buffer))))) + (sesman--link-session-interactively session 'buffer buf))) + +;;;###autoload +(defun sesman-link-with-directory (&optional dir session) + "Ask for SESSION and link with DIR. +DIR defaults to `default-directory'. On universal argument, or if DIR is 'ask, +ask for directory." + (interactive "P") + (let ((dir (if (or (eq dir 'ask) + (equal dir '(4))) + (read-directory-name "Link directory: ") + (or dir default-directory)))) + (sesman--link-session-interactively session 'directory dir))) + +;;;###autoload +(defun sesman-link-with-project (&optional project session) + "Ask for SESSION and link with PROJECT. +PROJECT defaults to current project. On universal argument, or if PROJECT is +'ask, ask for the project. SESSION defaults to the current session." + (interactive "P") + (let* ((system (sesman--system)) + (project (expand-file-name + (if (or (eq project 'ask) + (equal project '(4))) + ;; FIXME: should be a completion over all known projects for this system + (read-directory-name "Project: " (sesman-project system)) + (or project (sesman-project system)))))) + (sesman--link-session-interactively session 'project project))) + +;;;###autoload +(defun sesman-link-with-least-specific (&optional session) + "Ask for SESSION and link with the least specific context available. +Normally the least specific context is the project. If not in a project, link +with the `default-directory'. If `default-directory' is nil, link with current +buffer." + (interactive "P") + (sesman--link-session-interactively session nil nil)) + +;;;###autoload +(defun sesman-unlink () + "Break any of the previously created links." + (interactive) + (let* ((system (sesman--system)) + (links (or (sesman-current-links system) + (user-error "No %s links found" system)))) + (mapc #'sesman--unlink + (sesman--ask-for-link "Unlink: " links 'ask-all))) + (run-hooks 'sesman-post-command-hook)) + +(declare-function sesman-browser "sesman-browser") +;;;###autoload (autoload 'sesman-map "sesman" "Session management prefix keymap." t 'keymap) +(defvar sesman-map + (let (sesman-map) + (define-prefix-command 'sesman-map) + (define-key sesman-map (kbd "C-i") #'sesman-info) + (define-key sesman-map (kbd "i") #'sesman-info) + (define-key sesman-map (kbd "C-w") #'sesman-browser) + (define-key sesman-map (kbd "w") #'sesman-browser) + (define-key sesman-map (kbd "C-s") #'sesman-start) + (define-key sesman-map (kbd "s") #'sesman-start) + (define-key sesman-map (kbd "C-r") #'sesman-restart) + (define-key sesman-map (kbd "r") #'sesman-restart) + (define-key sesman-map (kbd "C-q") #'sesman-quit) + (define-key sesman-map (kbd "q") #'sesman-quit) + (define-key sesman-map (kbd "C-l") #'sesman-link-with-least-specific) + (define-key sesman-map (kbd "l") #'sesman-link-with-least-specific) + (define-key sesman-map (kbd "C-b") #'sesman-link-with-buffer) + (define-key sesman-map (kbd "b") #'sesman-link-with-buffer) + (define-key sesman-map (kbd "C-d") #'sesman-link-with-directory) + (define-key sesman-map (kbd "d") #'sesman-link-with-directory) + (define-key sesman-map (kbd "C-p") #'sesman-link-with-project) + (define-key sesman-map (kbd "p") #'sesman-link-with-project) + (define-key sesman-map (kbd "C-u") #'sesman-unlink) + (define-key sesman-map (kbd " u") #'sesman-unlink) + sesman-map) + "Session management prefix keymap.") + +(defvar sesman-menu + '("Sesman" + ["Show Session Info" sesman-info] + "--" + ["Start" sesman-start] + ["Restart" sesman-restart :active (sesman-current-session (sesman--system))] + ["Quit" sesman-quit :active (sesman-current-session (sesman--system))] + "--" + ["Link with Buffer" sesman-link-with-buffer :active (sesman-current-session (sesman--system))] + ["Link with Directory" sesman-link-with-directory :active (sesman-current-session (sesman--system))] + ["Link with Project" sesman-link-with-project :active (sesman-current-session (sesman--system))] + ["Unlink" sesman-unlink :active (sesman-current-session (sesman--system))] + "--" + ["Browser" sesman-browser :active (sesman-current-session (sesman--system))]) + "Sesman Menu.") + +(defun sesman-install-menu (map) + "Install `sesman-menu' into MAP." + (easy-menu-do-define 'sesman-menu-open + map + (get 'sesman-menu 'variable-documentation) + sesman-menu)) + + +;;; System Generic + +(cl-defgeneric sesman-start-session (system) + "Start and return SYSTEM SESSION.") + +(cl-defgeneric sesman-quit-session (system session) + "Terminate SYSTEM SESSION.") + +(cl-defgeneric sesman-restart-session (system session) + "Restart SYSTEM SESSION. +By default, calls `sesman-quit-session' and then +`sesman-start-session'." + (let ((old-name (car session))) + (sesman-quit-session system session) + (let ((new-session (sesman-start-session system))) + (setcar new-session old-name)))) + +(cl-defgeneric sesman-session-info (_system session) + "Return a plist with :objects key containing user \"visible\" objects. +Optional :strings value is a list of string representations of objects. Optional +:map key is a local keymap to place on every object in the session browser. +Optional :buffers is a list of buffers which will be used for navigation from +the session browser. If :buffers is missing, buffers from :objects are used +instead." + (list :objects (cdr session))) + +(cl-defgeneric sesman-project (_system) + "Retrieve project root in current directory (`default-directory') for SYSTEM. +Return a string or nil if no project has been found." + nil) + +(cl-defgeneric sesman-more-relevant-p (_system session1 session2) + "Return non-nil if SESSION1 should be sorted before SESSION2. +By default, sort by session name. Systems should overwrite this method to +provide a more meaningful ordering. If your system objects are buffers you can +use `sesman-more-recent-p' utility in this method." + (not (string-greaterp (car session1) (car session2)))) + +(cl-defgeneric sesman-friendly-session-p (_system _session) + "Return non-nil if SESSION is a friendly session in current context. +The \"friendship\" is system dependent but usually means sessions running in +dependent projects. Unless SYSTEM has defined a method for this generic, there +are no friendly sessions." + nil) + +(cl-defgeneric sesman-context-types (_system) + "Return a list of context types understood by SYSTEM. +Contexts must be sorted from most specific to least specific." + '(buffer directory project)) + + +;;; System API + +(defun sesman-session (system session-name) + "Retrieve SYSTEM's session with SESSION-NAME from global hash." + (let ((system (or system (sesman--system)))) + (gethash (cons system session-name) sesman-sessions-hashmap))) + +(defun sesman-sessions (system &optional sort type cxt-types) + "Return a list of sessions registered with SYSTEM. +When TYPE is either 'all or nil return all sessions registered with the SYSTEM, +when 'linked, only linked to the current context sessions, when 'friendly - only +friendly sessions. If SORT is non-nil, sessions are sorted in the relevance +order with linked sessions leading the list. CXT-TYPES is a list of context +types to consider for linked sessions." + (let ((system (or system (sesman--system)))) + (cond + ((eq type 'linked) + (sesman--linked-sessions system sort cxt-types)) + ((eq type 'friendly) + (sesman--friendly-sessions system sort)) + ((memq type '(all nil)) + (if sort + (delete-dups + (append (sesman--linked-sessions system 'sort cxt-types) + (sesman--all-system-sessions system 'sort))) + (sesman--all-system-sessions system))) + (t (error "Invalid session TYPE argument %s" type))))) + +(defun sesman-current-sessions (system &optional cxt-types) + "Return a list of SYSTEM sessions active in the current context. +Sessions are ordered by the relevance order and linked sessions come first. If +`sesman-use-friendly-sessions' current sessions consist of linked and friendly +sessions, otherwise only of linked sessions. CXT-TYPES is a list of context +types to consider. Defaults to the list returned from `sesman-context-types'." + (if sesman-use-friendly-sessions + (delete-dups + (append (sesman--linked-sessions system 'sort cxt-types) + (sesman--friendly-sessions system 'sort))) + (sesman--linked-sessions system 'sort cxt-types))) + +(defun sesman-current-session (system &optional cxt-types) + "Get the most relevant current session for the SYSTEM. +CXT-TYPES is a list of context types to consider." + (or (car (sesman--linked-sessions system 'sort cxt-types)) + (car (sesman--friendly-sessions system 'sort)))) + +(defun sesman-ensure-session (system &optional cxt-types) + "Get the most relevant linked session for SYSTEM or throw if none exists. +CXT-TYPES is a list of context types to consider." + (or (sesman-current-session system cxt-types) + (user-error "No linked %s sessions" system))) + +(defun sesman-has-sessions-p (system) + "Return t if there is at least one session registered with SYSTEM." + (let ((system (or system (sesman--system))) + (found)) + (condition-case nil + (maphash (lambda (k _) + (when (eq (car k) system) + (setq found t) + (throw 'found nil))) + sesman-sessions-hashmap) + (error)) + found)) + +(defvar sesman--select-session-history nil) +(defun sesman-ask-for-session (system prompt &optional sessions ask-new ask-all) + "Ask for a SYSTEM session with PROMPT. +SESSIONS defaults to value returned from `sesman-sessions'. If +ASK-NEW is non-nil, offer *new* option to start a new session. If +ASK-ALL is non-nil offer *all* option. If ASK-ALL is non-nil, +return a list of sessions, otherwise a single session." + (let* ((sessions (or sessions (sesman-sessions system))) + (name.syms (mapcar (lambda (s) + (let ((name (car s))) + (cons (if (symbolp name) (symbol-name name) name) + name))) + sessions)) + (nr (length name.syms)) + (syms (if (and (not ask-new) (= nr 0)) + (error "No %s sessions found" system) + (append name.syms + (when ask-new '(("*new*"))) + (when (and ask-all (> nr 1)) + '(("*all*")))))) + (def (caar syms)) + ;; (def (if (assoc (car sesman--select-session-history) syms) + ;; (car sesman--select-session-history) + ;; (caar syms))) + (sel (completing-read + prompt (mapcar #'car syms) nil t nil 'sesman--select-session-history def))) + (cond + ((string= sel "*new*") + (let ((ses (sesman-start-session system))) + (message "Started %s" (car ses)) + (if ask-all (list ses) ses))) + ((string= sel "*all*") + sessions) + (t + (let* ((sym (cdr (assoc sel syms))) + (ses (assoc sym sessions))) + (if ask-all (list ses) ses)))))) + +(defvar sesman--cxt-abbrevs '(buffer "buf" project "proj" directory "dir")) +(defun sesman--format-context (cxt-type cxt-val extra-face) + (let* ((face (intern (format "sesman-%s-face" cxt-type))) + (short-type (propertize (or (plist-get sesman--cxt-abbrevs cxt-type) + (symbol-value cxt-type)) + 'face (list (if (facep face) + face + 'font-lock-function-name-face) + extra-face)))) + (concat short-type + (propertize (format "(%s)" cxt-val) + 'face extra-face)))) + +(defun sesman-grouped-links (system session &optional current-first as-string) + "Retrieve all links for SYSTEM's SESSION from the global `sesman-links-alist'. +Return an alist of the form + + ((buffer buffers..) + (directory directories...) + (project projects...)). + +When `CURRENT-FIRST' is non-nil, a cons of two lists as above is returned with +car containing links relevant in current context and cdr all other links. If +AS-STRING is non-nil, return an equivalent string representation." + (let* ((system (or system (sesman--system))) + (session (or session (sesman-current-session system))) + (ses-name (car session)) + (links (thread-last sesman-links-alist + (seq-filter (sesman--link-lookup-fn system ses-name)) + (sesman--sort-links system) + (reverse))) + (out (mapcar (lambda (x) (list x)) + (sesman-context-types system))) + (out-rel (when current-first + (copy-alist out)))) + (mapc (lambda (link) + (let* ((type (sesman--lnk-context-type link)) + (entry (if (and current-first + (sesman-relevant-link-p link)) + (assoc type out-rel) + (assoc type out)))) + (when entry + (setcdr entry (cons link (cdr entry)))))) + links) + (let ((out (delq nil (mapcar (lambda (el) (and (cdr el) el)) out))) + (out-rel (delq nil (mapcar (lambda (el) (and (cdr el) el)) out-rel)))) + (if as-string + (let ((fmt-fn (lambda (typed-links) + (let* ((type (car typed-links))) + (mapconcat (lambda (lnk) + (let ((val (sesman--abbrev-path-maybe + (sesman--lnk-value lnk)))) + (sesman--format-context type val 'italic))) + (cdr typed-links) + ", "))))) + (if out-rel + (concat (mapconcat fmt-fn out-rel ", ") + (when out " | ") + (mapconcat fmt-fn out ", ")) + (mapconcat fmt-fn out ", "))) + (if current-first + (cons out-rel out) + out))))) + +(defun sesman-link-session (system session &optional cxt-type cxt-val) + "Link SYSTEM's SESSION to context give by CXT-TYPE and CXT-VAL. +If CXT-TYPE is nil, use the least specific type available in the current +context. If CXT-TYPE is non-nil, and CXT-VAL is not given, retrieve it with +`sesman-context'. See also `sesman-link-with-project', +`sesman-link-with-directory' and `sesman-link-with-buffer'." + (let* ((ses-name (or (car-safe session) + (error "SESSION must be a headed list"))) + (cxt-val (or cxt-val + (or (if cxt-type + (sesman-context cxt-type system) + (let ((cxt (sesman--least-specific-context system))) + (setq cxt-type (car cxt)) + (cdr cxt))) + (error "No local context of type %s" cxt-type)))) + (cxt-val (if (stringp cxt-val) + (expand-file-name cxt-val) + cxt-val)) + (key (cons system ses-name)) + (link (list key cxt-type cxt-val))) + (if (member cxt-type sesman-single-link-context-types) + (thread-last sesman-links-alist + (seq-remove (sesman--link-lookup-fn system nil cxt-type cxt-val)) + (cons link) + (setq sesman-links-alist)) + (unless (seq-filter (sesman--link-lookup-fn system ses-name cxt-type cxt-val) + sesman-links-alist) + (setq sesman-links-alist (cons link sesman-links-alist)))) + (run-hooks 'sesman-post-command-hook) + link)) + +(defun sesman-links (system &optional session-or-name cxt-types sort) + "Retrieve all links for SYSTEM, SESSION-OR-NAME and CXT-TYPES. +SESSION-OR-NAME can be either a session or a name of the session. If SORT is +non-nil links are sorted in relevance order and `sesman-current-links' lead the +list, otherwise links are returned in the creation order." + (let* ((ses-name (if (listp session-or-name) + (car session-or-name) + session-or-name)) + (lfn (sesman--link-lookup-fn system ses-name cxt-types))) + (if sort + (delete-dups (append + (sesman-current-links system ses-name) + (sesman--sort-links system (seq-filter lfn sesman-links-alist)))) + (seq-filter lfn sesman-links-alist)))) + +(defun sesman-current-links (system &optional session-or-name sort cxt-types) + "Retrieve all active links in current context for SYSTEM and SESSION-OR-NAME. +SESSION-OR-NAME can be either a session or a name of the session. CXT-TYPES is a +list of context types to consider. Returned links are a subset of +`sesman-links-alist' sorted in order of relevance if SORT is non-nil." + ;; mapcan is a built-in in 26.1; don't want to require cl-lib for one function + (let ((ses-name (if (listp session-or-name) + (car session-or-name) + session-or-name))) + (seq-mapcat + (lambda (cxt-type) + (let* ((lfn (sesman--link-lookup-fn system ses-name cxt-type)) + (links (seq-filter (lambda (l) + (and (funcall lfn l) + (sesman-relevant-context-p cxt-type (sesman--lnk-value l)))) + sesman-links-alist))) + (if sort + (sesman--sort-links system links) + links))) + (or cxt-types (sesman-context-types system))))) + +(defun sesman-has-links-p (system &optional cxt-types) + "Return t if there is at least one linked session. +CXT-TYPES defaults to `sesman-context-types' for current SYSTEM." + (let ((cxt-types (or cxt-types (sesman-context-types system))) + (found)) + (condition-case nil + (mapc (lambda (l) + (when (eq system (sesman--lnk-system-name l)) + (let ((cxt (sesman--lnk-context-type l))) + (when (and (member cxt cxt-types) + (sesman-relevant-context-p cxt (sesman--lnk-value l))) + (setq found t) + (throw 'found nil))))) + sesman-links-alist) + (error)) + found)) + +(defun sesman-register (system session) + "Register SESSION into `sesman-sessions-hashmap' and `sesman-links-alist'. +SYSTEM defaults to current system. If a session with same name is already +registered in `sesman-sessions-hashmap', change the name by appending \"#1\", +\"#2\" ... to the name. This function should be called by system-specific +connection initializers (\"run-xyz\", \"xyz-jack-in\" etc.)." + (let* ((system (or system (sesman--system))) + (ses-name (car session)) + (ses-name0 (car session)) + (i 1)) + (while (sesman-session system ses-name) + (setq ses-name (format "%s#%d" ses-name0 i) + i (1+ i))) + (setq session (cons ses-name (cdr session))) + (puthash (cons system ses-name) session sesman-sessions-hashmap) + (sesman-link-session system session) + session)) + +(defun sesman-unregister (system session) + "Unregister SESSION. +SYSTEM defaults to current system. Remove session from +`sesman-sessions-hashmap' and `sesman-links-alist'." + (let ((ses-key (cons system (car session)))) + (remhash ses-key sesman-sessions-hashmap) + (sesman--clear-links) + session)) + +(defun sesman-add-object (system session-name object &optional allow-new) + "Add (destructively) OBJECT to session SESSION-NAME of SYSTEM. +If ALLOW-NEW is nil and session with SESSION-NAME does not exist +throw an error, otherwise register a new session with +session (list SESSION-NAME OBJECT)." + (let* ((system (or system (sesman--system))) + (session (sesman-session system session-name))) + (if session + (setcdr session (cons object (cdr session))) + (if allow-new + (sesman-register system (list session-name object)) + (error "%s session '%s' does not exist" + (sesman--cap-system-name system) session-name))))) + +(defun sesman-remove-object (system session-name object &optional auto-unregister no-error) + "Remove (destructively) OBJECT from session SESSION-NAME of SYSTEM. +If SESSION-NAME is nil, retrieve the session with +`sesman-session-for-object'. If OBJECT is the last object in sesman +session, `sesman-unregister' the session. If AUTO-UNREGISTER is non-nil +unregister sessions of length 0 and remove all the links with the session. +If NO-ERROR is non-nil, don't throw an error if OBJECT is not found in any +session. This is useful if there are several \"concurrent\" parties which +can remove the object." + (let* ((system (or system (sesman--system))) + (session (if session-name + (sesman-session system session-name) + (sesman-session-for-object system object no-error))) + (new-session (delete object session))) + (cond ((null new-session)) + ((= (length new-session) 1) + (when auto-unregister + (sesman-unregister system session))) + (t + (puthash (cons system (car session)) new-session sesman-sessions-hashmap))))) + +(defun sesman-session-for-object (system object &optional no-error) + "Retrieve SYSTEM session which contains OBJECT. +When NO-ERROR is non-nil, don't throw an error if OBJECT is not part of any +session. In such case, return nil." + (let* ((system (or system (sesman--system))) + (sessions (sesman--all-system-sessions system))) + (or (seq-find (lambda (ses) + (seq-find (lambda (x) (equal object x)) (cdr ses))) + sessions) + (unless no-error + (error "%s is not part of any %s sessions" + object system))))) + +(defun sesman-session-name-for-object (system object &optional no-error) + "Retrieve the name of the SYSTEM's session containing OBJECT. +When NO-ERROR is non-nil, don't throw an error if OBJCECT is not part of +any session. In such case, return nil." + (car (sesman-session-for-object system object no-error))) + +(defun sesman-more-recent-p (bufs1 bufs2) + "Return t if BUFS1 is more recent than BUFS2. +BUFS1 and BUFS2 are either buffers or lists of buffers. When lists of +buffers, most recent buffers from each list are considered. To be used +primarily in `sesman-more-relevant-p' methods when session objects are +buffers." + (let ((bufs1 (if (bufferp bufs1) (list bufs1) bufs1)) + (bufs2 (if (bufferp bufs2) (list bufs2) bufs2))) + (eq 1 (seq-some (lambda (b) + (if (member b bufs1) + 1 + (when (member b bufs2) + -1))) + (buffer-list))))) + +;; path caching because file-truename is very slow +(defvar sesman--path-cache (make-hash-table :test #'equal)) +(defun sesman-expand-path (path) + "Expand PATH with optionally follow symlinks. +Whether symlinks are followed is controlled by `sesman-follow-symlinks' custom +variable. Always return the expansion without the trailing directory slash." + (directory-file-name + (if sesman-follow-symlinks + (let ((true-name (or (gethash path sesman--path-cache) + (puthash path (file-truename path) sesman--path-cache)))) + (if (or (eq sesman-follow-symlinks t) + vc-follow-symlinks) + true-name + ;; sesman-follow-symlinks is 'vc but vc-follow-symlinks is nil + (expand-file-name path))) + (expand-file-name path)))) + + +;;; Contexts + +(cl-defgeneric sesman-context (_cxt-type _system) + "Given SYSTEM and context type CXT-TYPE return the context.") +(cl-defmethod sesman-context ((_cxt-type (eql buffer)) _system) + "Return current buffer." + (current-buffer)) +(cl-defmethod sesman-context ((_cxt-type (eql directory)) _system) + "Return current directory." + (sesman-expand-path default-directory)) +(cl-defmethod sesman-context ((_cxt-type (eql project)) system) + "Return current project." + (let* ((default-directory (sesman-expand-path default-directory)) + (proj (or + (sesman-project (or system (sesman--system))) + ;; Normally we would use (project-roots (project-current)) but currently + ;; project-roots fails on nil and doesn't work on custom `('foo . + ;; "path/to/project"). So, use vc as a fallback and don't use project.el at + ;; all for now. + ;; NB: `vc-root-dir' doesn't work from symlinked files. Emacs Bug? + (vc-root-dir)))) + (when proj + (expand-file-name proj)))) + +(cl-defgeneric sesman-relevant-context-p (_cxt-type cxt) + "Non-nil if context CXT is relevant to current context of type CXT-TYPE.") +(cl-defmethod sesman-relevant-context-p ((_cxt-type (eql buffer)) buf) + "Non-nil if BUF is `current-buffer'." + (eq (current-buffer) buf)) +(cl-defmethod sesman-relevant-context-p ((_cxt-type (eql directory)) dir) + "Non-nil if DIR is the parent or equals the `default-directory'." + (when (and dir default-directory) + (string-match-p (concat "^" (sesman-expand-path dir)) + (sesman-expand-path default-directory)))) +(cl-defmethod sesman-relevant-context-p ((_cxt-type (eql project)) proj) + "Non-nil if PROJ is the parent or equal to the `default-directory'." + (when (and proj default-directory) + (string-match-p (concat "^" (sesman-expand-path proj)) + (sesman-expand-path default-directory)))) + +(defun sesman-relevant-link-p (link &optional cxt-types) + "Return non-nil if LINK is relevant to the current context. +If CXT-TYPES is non-nil, only check relevance for those contexts." + (when (or (null cxt-types) + (member (sesman--lnk-context-type link) cxt-types)) + (sesman-relevant-context-p + (sesman--lnk-context-type link) + (sesman--lnk-value link)))) + +(defun sesman-relevant-session-p (system session &optional cxt-types) + "Return non-nil if SYSTEM's SESSION is relevant to the current context. +If CXT-TYPES is non-nil, only check relevance for those contexts." + (seq-some #'sesman-relevant-link-p + (sesman-links system session cxt-types))) + +(define-obsolete-function-alias 'sesman-linked-sessions 'sesman--linked-sessions "v0.3.2") + +(provide 'sesman) + +;;; sesman.el ends here diff --git a/elpa/sesman-readme.txt b/elpa/sesman-readme.txt new file mode 100644 index 00000000..653b8954 --- /dev/null +++ b/elpa/sesman-readme.txt @@ -0,0 +1,3 @@ +Sesman provides facilities for session management and interactive session +association with the current contexts (project, directory, buffers etc). See +project's readme for more details. diff --git a/elpa/xml+-20170727.2351/xml+-autoloads.el b/elpa/xml+-20170727.2351/xml+-autoloads.el new file mode 100644 index 00000000..224b5ce3 --- /dev/null +++ b/elpa/xml+-20170727.2351/xml+-autoloads.el @@ -0,0 +1,15 @@ +;;; xml+-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil nil ("xml+.el") (23997 31593 860347 792000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; xml+-autoloads.el ends here diff --git a/elpa/xml+-20170727.2351/xml+-pkg.el b/elpa/xml+-20170727.2351/xml+-pkg.el new file mode 100644 index 00000000..4f8add0e --- /dev/null +++ b/elpa/xml+-20170727.2351/xml+-pkg.el @@ -0,0 +1,2 @@ +;;; -*- no-byte-compile: t -*- +(define-package "xml+" "20170727.2351" "Utilities for xml and html trees" '((emacs "24.4") (dash "2.12.0")) :commit "232fa863c08fc159b21dd58c39ea45dce3334895" :keywords '("xml" "html") :authors '(("Ben Dean" . "bendean837@gmail.com")) :maintainer '("Ben Dean" . "bendean837@gmail.com") :url "https://github.com/bddean/xml-plus") diff --git a/elpa/xml+-20170727.2351/xml+.el b/elpa/xml+-20170727.2351/xml+.el new file mode 100644 index 00000000..e090df83 --- /dev/null +++ b/elpa/xml+-20170727.2351/xml+.el @@ -0,0 +1,147 @@ +;;; xml+.el --- Utilities for xml and html trees + +;; Author: Ben Dean +;; Version: 0.0.0 +;; Package-Version: 20170727.2351 +;; Package-Requires: ((emacs "24.4") (dash "2.12.0")) +;; Keywords: xml, html +;; URL: https://github.com/bddean/xml-plus + +;; This program 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. + +;; This program 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 this program. If not, see . + + +;;; Commentary: + +;; Utility functions for xml parse trees. +;; - `xml+-query-all' and `xml+-query-first' are query functions that search +;; descendants in node lists. They don't work with namespace-aware parsing yet +;; +;; - `xml+-node-text' gets node text + +;;; Code: + +(require 'cl-lib) +(require 'dash) +(require 'subr-x) +(require 'xml) + +(defun xml+--node-matches (node matcher) + "Return non-nil if xml/html node NODE matches query selector +element MATCHER, an attribute-value plist optionally beginning +with a tag name or list of tag names, e.g. ((p div) :class +\"content\") + +Begin MATCHER with ~ to negate the match + +If MATCHER is a list of lists, it matches node if node matches +any of its members. +" + (if (eq (type-of node) 'string) + nil ;; TODO text matching + (let ((tags nil) + (text nil) + (negative nil)) + (setq matcher (-clone matcher)) + (if (-every? 'listp matcher) + (-any? `(lambda (m) (xml+--node-matches (quote ,node) m)) matcher) + (when (eq (car matcher) '~) + (setq negative t) + (setq matcher (cdr matcher))) + + (when (and matcher + (not (keywordp (cl-first matcher)))) + (setq tags (-flatten (list (pop matcher))))) + + (not (equal ;; xor + negative + (and + ;; Match tags + (or (not tags) (memq (xml-node-name node) tags)) + ;; Match attributes + (let ((matches t)) + (while (and matcher matches) + (when (not (keywordp (car matcher))) + (error (format "Expected keyword in matcher, got %s" + (symbol-name (type-of (car matcher)))))) + (setq matches + (equal (cdr (assoc (intern (substring (symbol-name (car matcher)) 1)) + (xml-node-attributes node))) + (cadr matcher))) + (setq matcher (cddr matcher))) + matches)))))))) + +(defun xml+-query--generic (just-one nodes query &optional result must-be-root) + "Recursive depth first search to collect one or all nodes in +NODES matching QUERY." + ;; Make cons cell to store a persistent reference to the result + (unless result (setq result (cons nil nil))) + (if (equal (car query) '>) + (xml+-query--generic just-one nodes (cdr query) result t) + (when (eq (type-of (car nodes)) 'symbol) + (setq nodes (list nodes))) + + (let ((nodes-remaining (-filter (lambda (n) (and n (listp n))) nodes)) + (node nil)) + + (while nodes-remaining + (setq node (pop nodes-remaining)) + (if (xml+--node-matches node (car query)) + (if (cdr query) + (xml+-query--generic just-one (xml-node-children node) (cdr query) result) + (setcdr result (append (cdr result) (list node))) + (when just-one (setq nodes-remaining nil))) + (unless must-be-root + (xml+-query--generic just-one (xml-node-children node) query result))))) + (reverse (cdr result)))) + +(defun xml+-query-all (nodes query &optional must-be-root) + "Search NODES for matches. +NODES is a single xml or html node or a list of them. + +QUERY is a list of node matchers optionally preceded by the +symbol `>'. Node matchers are usually descendant matchers. When +preceded by '> they are direct decendant matchers. + +For example, the analog to the Javascript call +document.querySelectorAll(\"body div#post > p.content\") is: + + (xml+-query-all document '((body) + (div :id \"post\") > + (p :class \"content\") + (a))) + +See also `xml-node-matches'" + (xml+-query--generic nil nodes query must-be-root)) + +(defun xml+-query-first (nodes query &optional must-be-root) + "Like `xml+-query-all', but only return the first match." + (car (xml+-query--generic t nodes query must-be-root))) + +(defun xml+-node-text (node) + "Get the text of NODE" + (string-trim + (replace-regexp-in-string "[\s\t\n]+" " " + (mapconcat 'concat (xml+-node-text--helper node) " ")))) + +(defun xml+-node-text--helper (node) + "Get the text of NODE" + (if (stringp node) + (list node) + (-reduce-from + (lambda (n1 n2) (append n1 (xml+-node-text--helper n2))) + nil + (xml-node-children node)))) + +(provide 'xml+) +;;; xml+.el ends here diff --git a/elpa/xml+-readme.txt b/elpa/xml+-readme.txt new file mode 100644 index 00000000..0ff9c579 --- /dev/null +++ b/elpa/xml+-readme.txt @@ -0,0 +1,5 @@ +Utility functions for xml parse trees. + - `xml+-query-all' and `xml+-query-first' are query functions that search + descendants in node lists. They don't work with namespace-aware parsing yet + + - `xml+-node-text' gets node text -- 2.47.3