├── .dir-locals.el ├── .github └── workflows │ ├── melpazoid.yml │ └── update-abbr.yml ├── .gitignore ├── CHANGELOG.org ├── LICENSE ├── Makefile ├── README.org ├── data └── abbreviations.json ├── lean4-eri.el ├── lean4-fringe.el ├── lean4-info.el ├── lean4-input.el ├── lean4-lake.el ├── lean4-mode.el ├── lean4-mode.info ├── lean4-mode.texi ├── lean4-settings.el ├── lean4-syntax.el └── lean4-util.el /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;; -*- no-byte-compile: t; -*- 2 | 3 | ((nil 4 | (bug-reference-url-format 5 | . "https://github.com/leanprover-community/lean4-mode/issues/%s"))) 6 | -------------------------------------------------------------------------------- /.github/workflows/melpazoid.yml: -------------------------------------------------------------------------------- 1 | # melpazoid build checks. 2 | 3 | # If your package is on GitHub, enable melpazoid's checks by copying this file 4 | # to .github/workflows/melpazoid.yml and modifying RECIPE and EXIST_OK below. 5 | 6 | name: melpazoid 7 | on: [push, pull_request] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Set up Python 3.10 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.10' 18 | - name: Install 19 | run: | 20 | python -m pip install --upgrade pip 21 | sudo apt-get install emacs && emacs --version 22 | git clone https://github.com/riscy/melpazoid.git ~/melpazoid 23 | pip install ~/melpazoid 24 | - name: Run 25 | env: 26 | LOCAL_REPO: ${{ github.workspace }} 27 | # RECIPE is your recipe as written for MELPA: 28 | RECIPE: >- 29 | (lean4-mode 30 | :fetcher github 31 | :repo "leanprover-community/lean4-mode" 32 | :files (:defaults ("data" "data/*.json"))) 33 | # set this to false (or remove it) if the package isn't on MELPA: 34 | # EXIST_OK: true 35 | run: echo $GITHUB_REF && make -C ~/melpazoid 36 | -------------------------------------------------------------------------------- /.github/workflows/update-abbr.yml: -------------------------------------------------------------------------------- 1 | name: Update abbreviations.json 2 | 3 | on: 4 | workflow_dispatch: 5 | workflow_call: 6 | 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | 13 | - run: | 14 | curl "$src" | jq 'del(.[] | select(. | match("\\$CURSOR")))' \ 15 | > data/abbreviations.json 16 | env: 17 | src: https://raw.githubusercontent.com/leanprover/vscode-lean4/master/lean4-unicode-input/src/abbreviations.json 18 | 19 | - uses: peter-evans/create-pull-request@v4 20 | with: 21 | title: 'Update abbreviations.json' 22 | commit-message: 'chore: update abbreviations.json' 23 | branch: update-abbreviations 24 | labels: automation,update 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cask 2 | *.elc 3 | -------------------------------------------------------------------------------- /CHANGELOG.org: -------------------------------------------------------------------------------- 1 | #+title: Lean4-Mode - Changelog 2 | #+language: en 3 | 4 | * Version 1.1.2 5 | 6 | - Fix occasional errors like "The connected server(s) does not support 7 | method =$/lean/plainGoal=" by not wrapping invocations of 8 | ~lsp-protocol~ macro into ~eval-when-compile~ but rather into 9 | ~eval-and-compile~. Thus, the methods should now work, no matter 10 | whether Lean4-Mode was loaded by interpreting =.el= Elisp code or by 11 | loading compiled =.elc= or =.eln= files. ([[https://github.com/leanprover-community/lean4-mode/issues/54][Bug#54]], [[https://leanprover.zulipchat.com/#narrow/channel/468104-Emacs/topic/lsp-mode.20errors.20due.20to.20list.20!.3D.20hash-table][Zulip discussion]]) 12 | 13 | * Version 1.1.1 14 | 15 | - Assign all customizable user-options to the Lean4-Mode specific 16 | =lean4= group. To customize Lean4-Mode, you now need to type =M-x 17 | customize-group RET lean4 RET=. 18 | 19 | * Version 1.1.0 20 | 21 | - To =lean4= customization group, add link to local info manual and 22 | use Lean4-Mode Github URL as website. 23 | - Introduce new dependency on Elpa package =compat=. 24 | - Remove dependency on Elpa package Flycheck. It is still supported 25 | but not required. 26 | 27 | * Version 1.0.1 28 | 29 | - Specify Yury G. Kudryashov as maintainer. 30 | - Rework README. (Now in Org format). 31 | - Provide README as Texi and Info manual too. 32 | 33 | * Version 1.0 34 | 35 | - Specify "Version" in Emacs-Lisp library header. 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # GNU- and NonGNU-Elpa accept Org files as package documentation but 2 | # Melpa does not. As long as Lean4-Mode is not distributed on GNU- or 3 | # NonGNU-Elpa, it should ship with .texi and .info manuals. This 4 | # depends on: GNU Emacs, Make and GNU Texinfo. 5 | 6 | lean4-mode.info lean4-mode.texi: README.org 7 | emacs --batch \ 8 | "--eval=(require 'ox-texinfo)" \ 9 | '--eval=(find-file "$<")' \ 10 | '--eval=(org-texinfo-export-to-info)' 11 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+title: Lean4-Mode - Emacs major mode for Lean language 2 | #+language: en 3 | #+export_file_name: lean4-mode.texi 4 | #+texinfo_dir_category: Emacs misc features 5 | #+texinfo_dir_title: Lean4-Mode: (lean4-mode). 6 | #+texinfo_dir_desc: Emacs major mode for Lean language 7 | 8 | This package extends [[https://www.gnu.org/software/emacs/][GNU Emacs]] by providing a major mode for editing 9 | code written in version 4 of the programming language and theorem 10 | prover [[https://lean-lang.org][Lean]]. 11 | 12 | The Lean4-Mode source code is developed at [[https://github.com/leanprover-community/lean4-mode][Github]] and its issues 13 | tracked there too. Further discussions and question-answering takes 14 | place in the [[https://leanprover.zulipchat.com/#narrow/channel/468104-Emacs][#Emacs channel]] of Lean's Zulip chat. 15 | 16 | For legacy version 3 of Lean, use the archived [[https://github.com/leanprover/lean3-mode][Lean3-Mode]] (also known 17 | as /Lean-Mode/). 18 | 19 | * Installation 20 | 21 | ** Brief and Generic Instructions 22 | 23 | First, install the dependencies of Lean4-Mode: 24 | - [[https://lean-lang.org/lean4/doc/setup.html][Lean]] (version 4) 25 | - Emacs (version 27 or later) 26 | - Emacs packages [[https://github.com/magnars/dash.el][Dash]] (available on GNU-Elpa), [[https://emacs-lsp.github.io/lsp-mode][lsp-mode]], and 27 | [[https://github.com/magit/magit/blob/main/lisp/magit-section.el][Magit-Section]] (available on Melpa) 28 | 29 | Second, install Lean4-Mode itself: 30 | - Clone the [[https://github.com/leanprover-community/lean4-mode][Git repository of Lean4-Mode]]. 31 | - In your [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html][Emacs initialization file]], add the path to that local 32 | repository to the ~load-path~ list. 33 | # Note that (require 'lean4-mode) is not necessary when the user 34 | # relies on autoloading and uses the default settings. 35 | 36 | ** Detailed and Concrete Instructions 37 | 38 | Install Lean version 4. 39 | 40 | Install Emacs version 27 or later. 41 | 42 | Install the Emacs packages Dash, lsp-mode and Magit-Section. Dash is 43 | the only one of these packages that is available in the default [[https://elpa.gnu.org][GNU 44 | Elpa]] package-archive. You can install the remaining packages either 45 | from source or from [[https://melpa.org/#/getting-started][Melpa]] package-archive. For later approach, add 46 | the following to your Emacs initialization file 47 | (e.g. =~/.emacs.d/init.el=): 48 | 49 | #+begin_src elisp 50 | (require 'package) 51 | 52 | (add-to-list 'package-archives 53 | '("melpa" . "https://melpa.org/packages/")) 54 | 55 | (add-to-list 'package-selected-packages 'dash) 56 | (add-to-list 'package-selected-packages 'lsp-mode) 57 | (add-to-list 'package-selected-packages 'magit-section) 58 | 59 | (package-refresh-contents) 60 | (package-install-selected-packages 'no-confirm) 61 | #+end_src 62 | 63 | Clone the Git repository of Lean4-Mode: 64 | 65 | #+begin_src shell 66 | git clone https://github.com/leanprover-community/lean4-mode.git ~/path/to/lean4-mode 67 | #+end_src 68 | 69 | In your Emacs initialization file, add the path to your local 70 | Lean4-Mode repository to the ~load-path~ list: 71 | #+begin_src elisp 72 | (add-to-list 'load-path "~/path/to/lean4-mode") 73 | #+end_src 74 | 75 | Lean4-Mode should now already be enabled when you open a file with 76 | =.lean= extension. But you can optionally also already load 77 | Lean4-Mode on Emacs startup, e.g. in order to customize variables: 78 | #+begin_src elisp 79 | (require 'lean4-mode) 80 | #+end_src 81 | 82 | ** Instructions for Source-Based Use-Package 83 | 84 | If you use a source-based package-manager (e.g. =package-vc.el=, 85 | Straight or Elpaca), then make sure to list the ="data"= directory in 86 | your Lean4-Mode package recipe. 87 | 88 | If you use the ~use-package~ macro and intent to defer loading of 89 | packages in order to improve your Emacs startup time, then make sure 90 | to specify ~lean4-mode~ as a =:command=. 91 | 92 | Following subsections show concrete examples. 93 | 94 | *** Native =:vc= (Emacs 30 or later) 95 | 96 | GNU Emacs comes with =use-package.el= built-in since version 29. And 97 | since version 30, it also comes with a built-in =:vc= keyword for the 98 | ~use-package~ macro that utilizes =package-vc.el= to install Emacs 99 | packages from remote source repositories. 100 | 101 | #+begin_src elisp 102 | (require 'package) 103 | (add-to-list 'package-archives 104 | '("melpa" . "https://melpa.org/packages/")) 105 | (package-initialize) 106 | 107 | (use-package lean4-mode 108 | :commands lean4-mode 109 | :vc (:url "https://github.com/leanprover-community/lean4-mode.git" 110 | :rev :last-release 111 | ;; Or, if you prefer the bleeding edge version of Lean4-Mode: 112 | ;; :rev :newest 113 | )) 114 | #+end_src 115 | 116 | *** Doom-Emacs 117 | 118 | If you use Doom-Emacs, you can place the following code in your Doom 119 | initialization file: 120 | 121 | #+begin_src elisp 122 | (package! lean4-mode 123 | :recipe (:host github 124 | :repo "leanprover-community/lean4-mode" 125 | :files ("*.el" "data"))) 126 | #+end_src 127 | 128 | *** Straight 129 | 130 | If you use the Straight package manager through Use-Package, then 131 | place the following code in your Emacs initialization file: 132 | 133 | #+begin_src elisp 134 | (use-package lean4-mode 135 | :commands lean4-mode 136 | :straight (lean4-mode :type git :host github 137 | :repo "leanprover-community/lean4-mode" 138 | :files ("*.el" "data"))) 139 | #+end_src 140 | 141 | * Usage 142 | 143 | If things are working correctly, you should see the word "Lean 4" in 144 | Emacs mode-line when you open a file with =.lean= extension. Emacs 145 | will ask you to identify the /project/ this file belongs to. If you 146 | then type =#check id=, the word =#check= will be underlined, and 147 | hovering over it will show you the type of ~id~. 148 | 149 | To view the proof state, run ~lean4-toggle-info~ (=C-c C-i=). This 150 | will display the =*Lean Goals*= buffer (like the Lean Info-View pane 151 | in VS-Code) in a separate window. 152 | 153 | | Key | Description | Command | 154 | |------------------------+--------------------------------------------------------+-----------------------------------| 155 | | =C-c C-k= | Echo the keystroke needed to input the symbol at point | ~quail-show-key~ | 156 | | =C-c C-d= | Recompile and reload imports | ~lean4-refresh-file-dependencies~ | 157 | | =C-c C-x= or =C-c C-l= | Execute Lean in stand-alone mode | ~lean4-std-exe~ | 158 | | =C-c C-p C-l= | Builds package with lake | ~lean4-lake-build~ | 159 | | =C-c C-i= | Toggle Info-View which shows goals and errors at point | ~lean4-toggle-info-buffer~ | 160 | 161 | ** lsp-mode 162 | 163 | For key bindings from lsp-mode, see [[https://emacs-lsp.github.io/lsp-mode/page/keybindings/][its respective documentation]] and 164 | note that not all capabilities are supported by Lean4-Mode. 165 | 166 | ** Flycheck 167 | 168 | You may optionally use Lean4-Mode together with Flycheck. In that 169 | case, the mode-line will show =FlyC:E/N=, indicating that there are 170 | =E= number of errors and =N= number of notes. Following keys will be 171 | available by default (via ~flycheck-mode-map~): 172 | 173 | | Key | Description | Command | 174 | |-----------+----------------------+---------------------------| 175 | | =C-c ! n= | Go to next error | ~flycheck-next-error~ | 176 | | =C-c ! p= | Go to previous error | ~flycheck-previous-error~ | 177 | 178 | * Configuration 179 | 180 | ** lsp-mode 181 | 182 | If you want breadcrumbs of namespaces and sections to be shown in the 183 | header-line, set the user option ~lsp-headerline-breadcrumb-enable~ to 184 | ~t~. 185 | 186 | ** Flycheck 187 | 188 | Flycheck is an optional but supported dependency of Lean4-Mode. If 189 | Flycheck is installed, lsp-mode and thus Lean4-Mode will by default 190 | use it. If you want to customize this behavior, e.g. if you'd like to 191 | use Emacs' built-in Flymake package instead of Flycheck while keeping 192 | later installed, then customize the ~lsp-diagnostics-provider~ user 193 | option accordingly. 194 | 195 | * Common Pitfalls 196 | 197 | Lean4-Mode only supports version 4 of Lean. For editing Lean version 198 | 3, use [[https://github.com/leanprover/lean3-mode][Lean3-Mode]], which is also known as Lean-Mode due to historical 199 | reasons. In principle, it is fine to have both Lean3-Mode and 200 | Lean4-Mode installed at the same time. But note that Lean3-Mode uses 201 | the prefix =lean-= for its symbols. E.g. you should not use 202 | =lean-=-prefixed commands in a buffer with Lean4-Mode as major mode. 203 | -------------------------------------------------------------------------------- /data/abbreviations.json: -------------------------------------------------------------------------------- 1 | { 2 | "\\": "\\", 3 | "a": "α", 4 | "b": "β", 5 | "c": "χ", 6 | "d": "↓", 7 | "e": "ε", 8 | "g": "γ", 9 | "i": "∩", 10 | "m": "μ", 11 | "n": "¬", 12 | "o": "∘", 13 | "p": "Π", 14 | "t": "▸", 15 | "r": "→", 16 | "u": "↑", 17 | "v": "∨", 18 | "x": "×", 19 | "-": "⁻¹", 20 | "~": "∼", 21 | ".": "·", 22 | "*": "⋆", 23 | "?": "¿", 24 | "1": "₁", 25 | "2": "₂", 26 | "3": "₃", 27 | "4": "₄", 28 | "5": "₅", 29 | "6": "₆", 30 | "7": "₇", 31 | "8": "₈", 32 | "9": "₉", 33 | "0": "₀", 34 | "l": "←", 35 | "<": "⟨", 36 | ">": "⟩", 37 | "O": "Ø", 38 | "&": "⅋", 39 | "A": "𝔸", 40 | "C": "ℂ", 41 | "D": "Δ", 42 | "F": "𝔽", 43 | "G": "Γ", 44 | "H": "ℍ", 45 | "I": "⋂", 46 | "I0": "⋂₀", 47 | "K": "𝕂", 48 | "L": "Λ", 49 | "N": "ℕ", 50 | "P": "Π", 51 | "Q": "ℚ", 52 | "R": "ℝ", 53 | "S": "Σ", 54 | "U": "⋃", 55 | "U0": "⋃₀", 56 | "Z": "ℤ", 57 | "#": "♯", 58 | ":": "∶", 59 | "|": "∣", 60 | "!": "¡", 61 | "be": "β", 62 | "ga": "γ", 63 | "de": "δ", 64 | "ep": "ε", 65 | "ze": "ζ", 66 | "et": "η", 67 | "th": "θ", 68 | "io": "ι", 69 | "ka": "κ", 70 | "la": "λ", 71 | "mu": "μ", 72 | "nu": "ν", 73 | "xi": "ξ", 74 | "pi": "π", 75 | "rh": "ρ", 76 | "vsi": "ς", 77 | "si": "σ", 78 | "ta": "τ", 79 | "ph": "φ", 80 | "ch": "χ", 81 | "ps": "ψ", 82 | "om": "ω", 83 | "`A": "À", 84 | "'A": "Á", 85 | "^{A}": "Â", 86 | "~A": "Ã", 87 | "\"A": "Ä", 88 | "cC": "Ç", 89 | "`E": "È", 90 | "'E": "É", 91 | "^{E}": "Ê", 92 | "\"E": "Ë", 93 | "`I": "Ì", 94 | "'I": "Í", 95 | "^{I}": "Î", 96 | "\"I": "Ï", 97 | "~N": "Ñ", 98 | "`O": "Ò", 99 | "'O": "Ó", 100 | "^{O}": "Ô", 101 | "~O": "Õ", 102 | "\"O": "Ö", 103 | "/O": "Ø", 104 | "`U": "Ù", 105 | "'U": "Ú", 106 | "^{U}": "Û", 107 | "\"U": "Ü", 108 | "'Y": "Ý", 109 | "`a": "à", 110 | "'a": "á", 111 | "^{a}": "â", 112 | "~a": "ã", 113 | "\"a": "ä", 114 | "cc": "ç", 115 | "`e": "è", 116 | "'e": "é", 117 | "^{e}": "ê", 118 | "\"e": "ë", 119 | "`i": "ì", 120 | "'i": "í", 121 | "^{i}": "î", 122 | "\"i": "ï", 123 | "~{n}": "ñ", 124 | "`o": "ò", 125 | "'o": "ó", 126 | "^{o}": "ô", 127 | "~o": "õ", 128 | "\"o": "ö", 129 | "/o": "ø", 130 | "`u": "ù", 131 | "'u": "ú", 132 | "^{u}": "û", 133 | "\"u": "ü", 134 | "'y": "ý", 135 | "\"y": "ÿ", 136 | "/L": "Ł", 137 | "notin": "∉", 138 | "note": "♩", 139 | "not": "¬", 140 | "nomisma": "𐆎", 141 | "nin": "∉", 142 | "nni": "∌", 143 | "ni": "∋", 144 | "nattrans": "⟹", 145 | "nat_trans": "⟹", 146 | "natural": "♮", 147 | "nat": "ℕ", 148 | "naira": "₦", 149 | "nabla": "∇", 150 | "napprox": "≉", 151 | "numero": "№", 152 | "nLeftarrow": "⇍", 153 | "nLeftrightarrow": "⇎", 154 | "nRightarrow": "⇏", 155 | "nVDash": "⊯", 156 | "nVdash": "⊮", 157 | "ncong": "≇", 158 | "nearrow": "↗", 159 | "neg": "¬", 160 | "nequiv": "≢", 161 | "neq": "≠", 162 | "nexists": "∄", 163 | "ne": "≠", 164 | "ngeqq": "≱", 165 | "ngeqslant": "≱", 166 | "ngeq": "≱", 167 | "ngtr": "≯", 168 | "nleftarrow": "↚", 169 | "nleftrightarrow": "↮", 170 | "nleqq": "≰", 171 | "nleqslant": "≰", 172 | "nleq": "≰", 173 | "nless": "≮", 174 | "nmid": "∤", 175 | "nparallel": "∦", 176 | "npreceq": "⋠", 177 | "nprec": "⊀", 178 | "nrightarrow": "↛", 179 | "nshortmid": "∤", 180 | "nsimeq": "≄", 181 | "nsim": "≁", 182 | "nsubseteqq": "⊈", 183 | "nsubseteq": "⊈", 184 | "nsubset": "⊄", 185 | "nsucceq": "⋡", 186 | "nsucc": "⊁", 187 | "nsupseteqq": "⊉", 188 | "nsupseteq": "⊉", 189 | "nsupset": "⊅", 190 | "ntrianglelefteq": "⋬", 191 | "ntriangleleft": "⋪", 192 | "ntrianglerighteq": "⋭", 193 | "ntriangleright": "⋫", 194 | "nvDash": "⊭", 195 | "nvdash": "⊬", 196 | "nwarrow": "↖", 197 | "eqn": "≠", 198 | "equiv": "≃", 199 | "eqcirc": "≖", 200 | "eqcolon": "≕", 201 | "eqslantgtr": "⋝", 202 | "eqslantless": "⋜", 203 | "entails": "⊢", 204 | "en": "–", 205 | "exn": "∄", 206 | "exists": "∃", 207 | "ex": "∃", 208 | "emptyset": "∅", 209 | "empty": "∅", 210 | "em": "—", 211 | "epsilon": "ε", 212 | "eps": "ε", 213 | "euro": "€", 214 | "eta": "η", 215 | "ell": "ℓ", 216 | "iso": "≅", 217 | "in": "∈", 218 | "inn": "∉", 219 | "inter": "∩", 220 | "intercal": "⊺", 221 | "intersection": "∩", 222 | "integral": "∫", 223 | "integral-": "⨍", 224 | "int": "ℤ", 225 | "inv": "⁻¹", 226 | "increment": "∆", 227 | "inf": "⊓", 228 | "infi": "⨅", 229 | "infty": "∞", 230 | "iff": "↔", 231 | "imp": "→", 232 | "imath": "ı", 233 | "iota": "ι", 234 | "=n": "≠", 235 | "==n": "≢", 236 | "===": "≣", 237 | "==>": "⟹", 238 | "==": "≡", 239 | "=:": "≕", 240 | "=o": "≗", 241 | "=>n": "⇏", 242 | "=>": "⇒", 243 | "~n": "≁", 244 | "~~n": "≉", 245 | "~~~": "≋", 246 | "~~-": "≊", 247 | "~~": "≈", 248 | "~-n": "≄", 249 | "~-": "≃", 250 | "~=n": "≇", 251 | "~=": "≅", 252 | "homotopy": "∼", 253 | "hom": "⟶", 254 | "hori": "ϩ", 255 | "hookleftarrow": "↩", 256 | "hookrightarrow": "↪", 257 | "hryvnia": "₴", 258 | "heta": "ͱ", 259 | "heartsuit": "♥", 260 | "hbar": "ℏ", 261 | ":~": "∻", 262 | ":=": "≔", 263 | "::-": "∺", 264 | "::": "∷", 265 | "-~": "≂", 266 | "-|": "⊣", 267 | "-1": "⁻¹", 268 | "^-1": "⁻¹", 269 | "-2": "⁻²", 270 | "-3": "⁻³", 271 | "-:": "∹", 272 | "->n": "↛", 273 | "->": "→", 274 | "-->": "⟶", 275 | "---": "─", 276 | "--=": "═", 277 | "--_": "━", 278 | "--.": "╌", 279 | "-o": "⊸", 280 | ".=.": "≑", 281 | ".=": "≐", 282 | ".+": "∔", 283 | ".-": "∸", 284 | "...": "⋯", 285 | "(=": "≘", 286 | "(b": "⟅", 287 | "and=": "≙", 288 | "and": "∧", 289 | "an": "∧", 290 | "angle": "∠", 291 | "rightangle": "∟", 292 | "angstrom": "Å", 293 | "all": "∀", 294 | "allf": "∀ᶠ", 295 | "all^f": "∀ᶠ", 296 | "allm": "∀ᵐ", 297 | "all^m": "∀ᵐ", 298 | "alpha": "α", 299 | "aleph": "ℵ", 300 | "aleph0": "ℵ₀", 301 | "asterisk": "⁎", 302 | "ast": "∗", 303 | "asymp": "≍", 304 | "apl": "⌶", 305 | "approxeq": "≊", 306 | "approx": "≈", 307 | "aa": "å", 308 | "ae": "æ", 309 | "austral": "₳", 310 | "afghani": "؋", 311 | "amalg": "∐", 312 | "average": "⨍", 313 | "-int": "⨍", 314 | "or=": "≚", 315 | "ordfeminine": "ª", 316 | "ordmasculine": "º", 317 | "or": "∨", 318 | "oplus": "⊕", 319 | "od": "ᵒᵈ", 320 | "orderdual": "ᵒᵈ", 321 | "addopposite": "ᵃᵒᵖ", 322 | "aop": "ᵃᵒᵖ", 323 | "mulopposite": "ᵐᵒᵖ", 324 | "mop": "ᵐᵒᵖ", 325 | "opposite": "ᵒᵖ", 326 | "op": "ᵒᵖ", 327 | "o+": "⊕", 328 | "o--": "⊖", 329 | "o-": "⊝", 330 | "ox": "⊗", 331 | "o/": "⊘", 332 | "o.": "⊙", 333 | "oo": "⊚", 334 | "o*": "∘*", 335 | "o=": "⊜", 336 | "oe": "œ", 337 | "octagonal": "🛑", 338 | "ohm": "Ω", 339 | "ounce": "℥", 340 | "omega": "ω", 341 | "omicron": "ο", 342 | "ominus": "⊖", 343 | "odot": "⊙", 344 | "oint": "∮", 345 | "oiint": "∯", 346 | "oslash": "⊘", 347 | "otimes": "⊗", 348 | "tensorproduct": "⊗", 349 | "pitensorproduct": "⨂", 350 | "tensorpower": "⨂", 351 | "pd": "∂", 352 | "*=": "≛", 353 | "t=": "≜", 354 | "tint": "∯", 355 | "transport": "▹", 356 | "trans": "▹", 357 | "triangledown": "▿", 358 | "trianglelefteq": "⊴", 359 | "triangleleft": "◃", 360 | "triangleq": "≜", 361 | "trianglerighteq": "⊵", 362 | "triangleright": "▹", 363 | "triangle": "▵", 364 | "tr": "⬝", 365 | "tb": "◂", 366 | "twoheadleftarrow": "↞", 367 | "twoheadrightarrow": "↠", 368 | "tw": "◃", 369 | "tie": "⁀", 370 | "times": "×", 371 | "theta": "θ", 372 | "therefore": "∴", 373 | "thickapprox": "≈", 374 | "thicksim": "∼", 375 | "telephone": "℡", 376 | "tenge": "₸", 377 | "textmusicalnote": "♪", 378 | "textmu": "µ", 379 | "textfractionsolidus": "⁄", 380 | "textbaht": "฿", 381 | "textdied": "✝", 382 | "textdiscount": "⁒", 383 | "textcolonmonetary": "₡", 384 | "textcircledP": "℗", 385 | "textwon": "₩", 386 | "textnaira": "₦", 387 | "textnumero": "№", 388 | "textpeso": "₱", 389 | "textpertenthousand": "‱", 390 | "textlira": "₤", 391 | "textlquill": "⁅", 392 | "textrecipe": "℞", 393 | "textreferencemark": "※", 394 | "textrquill": "⁆", 395 | "textinterrobang": "‽", 396 | "textestimated": "℮", 397 | "textopenbullet": "◦", 398 | "tugrik": "₮", 399 | "tau": "τ", 400 | "top": "⊤", 401 | "to": "→", 402 | "to0": "→₀", 403 | "r0": "→₀", 404 | "to_0": "→₀", 405 | "r_0": "→₀", 406 | "finsupp": "→₀", 407 | "to1": "→₁", 408 | "r1": "→₁", 409 | "to_1": "→₁", 410 | "r_1": "→₁", 411 | "l1": "→₁", 412 | "to1s": "→₁ₛ", 413 | "r1s": "→₁ₛ", 414 | "to_1s": "→₁ₛ", 415 | "r_1s": "→₁ₛ", 416 | "l1simplefunc": "→₁ₛ", 417 | "toa": "→ₐ", 418 | "ra": "→ₐ", 419 | "to_a": "→ₐ", 420 | "r_a": "→ₐ", 421 | "alghom": "→ₐ", 422 | "tob": "→ᵇ", 423 | "rb": "→ᵇ", 424 | "to^b": "→ᵇ", 425 | "r^b": "→ᵇ", 426 | "boundedcontinuousfunction": "→ᵇ", 427 | "tol": "→ₗ", 428 | "rl": "→ₗ", 429 | "to_l": "→ₗ", 430 | "r_l": "→ₗ", 431 | "linearmap": "→ₗ", 432 | "tom": "→ₘ", 433 | "rm": "→ₘ", 434 | "to_m": "→ₘ", 435 | "r_m": "→ₘ", 436 | "aeeqfun": "→ₘ", 437 | "rp": "→ₚ", 438 | "to_p": "→ₚ", 439 | "r_p": "→ₚ", 440 | "dfinsupp": "→ₚ", 441 | "tos": "→ₛ", 442 | "rs": "→ₛ", 443 | "to_s": "→ₛ", 444 | "r_s": "→ₛ", 445 | "simplefunc": "→ₛ", 446 | "heyting": "⇨", 447 | "himp": "⇨", 448 | "hnot": "¬", 449 | "covers": "⋖", 450 | "covby": "⋖", 451 | "wcovby": "⩿", 452 | "wcovers": "⩿", 453 | "def=": "≝", 454 | "defs": "≙", 455 | "degree": "°", 456 | "dei": "ϯ", 457 | "delta": "δ", 458 | "doteqdot": "≑", 459 | "doteq": "≐", 460 | "dotplus": "∔", 461 | "dotsquare": "⊡", 462 | "dot": "⬝", 463 | "dong": "₫", 464 | "downarrow": "↓", 465 | "downdownarrows": "⇊", 466 | "downleftharpoon": "⇃", 467 | "downrightharpoon": "⇂", 468 | "dr-": "↘", 469 | "dr=": "⇘", 470 | "drachma": "₯", 471 | "dr": "↘", 472 | "dl-": "↙", 473 | "dl=": "⇙", 474 | "dl": "↙", 475 | "d-2": "⇊", 476 | "d-u-": "⇵", 477 | "d-|": "↧", 478 | "d-": "↓", 479 | "d==": "⟱", 480 | "d=": "⇓", 481 | "dd-": "↡", 482 | "ddagger": "‡", 483 | "ddag": "‡", 484 | "ddots": "⋱", 485 | "dz": "↯", 486 | "dib": "◆", 487 | "diw": "◇", 488 | "di.": "◈", 489 | "die": "⚀", 490 | "division": "÷", 491 | "divideontimes": "⋇", 492 | "div": "÷", 493 | "diameter": "⌀", 494 | "diamondsuit": "♢", 495 | "diamond": "⋄", 496 | "digamma": "ϝ", 497 | "di": "◆", 498 | "dagger": "†", 499 | "dag": "†", 500 | "daleth": "ℸ", 501 | "dashv": "⊣", 502 | "dh": "ð", 503 | "dvd": "∣", 504 | "m=": "≞", 505 | "meet": "⊓", 506 | "member": "∈", 507 | "mem": "∈", 508 | "measuredangle": "∡", 509 | "mapsto": "↦", 510 | "male": "♂", 511 | "maltese": "✠", 512 | "manat": "₼", 513 | "mathscr{I}": "ℐ", 514 | "minus": "−", 515 | "mill": "₥", 516 | "micro": "µ", 517 | "mid": "∣", 518 | "multiplication": "×", 519 | "multimap": "⊸", 520 | "mho": "℧", 521 | "models": "⊧", 522 | "mp": "∓", 523 | "?=": "≟", 524 | "??": "⁇", 525 | "?!": "‽", 526 | "prohibited": "🛇", 527 | "prod": "∏", 528 | "propto": "∝", 529 | "precapprox": "≾", 530 | "preceq": "≼", 531 | "precnapprox": "⋨", 532 | "precnsim": "⋨", 533 | "precsim": "≾", 534 | "prec": "≺", 535 | "preim": "⁻¹'", 536 | "preimage": "⁻¹'", 537 | "prime": "′", 538 | "pr": "↣", 539 | "powerset": "𝒫", 540 | "pounds": "£", 541 | "pound": "£", 542 | "pab": "▰", 543 | "paw": "▱", 544 | "partnership": "㉐", 545 | "partial": "∂", 546 | "paragraph": "¶", 547 | "parallel": "∥", 548 | "pa": "▰", 549 | "pm": "±", 550 | "perp": "⟂", 551 | "^perp": "ᗮ", 552 | "permil": "‰", 553 | "per": "⅌", 554 | "peso": "₱", 555 | "peseta": "₧", 556 | "pilcrow": "¶", 557 | "pitchfork": "⋔", 558 | "psi": "ψ", 559 | "phi": "φ", 560 | "leqn": "≰", 561 | "leqq": "≦", 562 | "leqslant": "≤", 563 | "leq": "≤", 564 | "len": "≰", 565 | "leadsto": "↝", 566 | "leftarrowtail": "↢", 567 | "leftarrow": "←", 568 | "leftharpoondown": "↽", 569 | "leftharpoonup": "↼", 570 | "leftleftarrows": "⇇", 571 | "leftrightarrows": "⇆", 572 | "leftrightarrow": "↔", 573 | "leftrightharpoons": "⇋", 574 | "leftrightsquigarrow": "↭", 575 | "leftthreetimes": "⋋", 576 | "lessapprox": "≲", 577 | "lessdot": "⋖", 578 | "lesseqgtr": "⋚", 579 | "lesseqqgtr": "⋚", 580 | "lessgtr": "≶", 581 | "lesssim": "≲", 582 | "le": "≤", 583 | "lub": "⊔", 584 | "lr--": "⟷", 585 | "lr-n": "↮", 586 | "lr-": "↔", 587 | "lr=n": "⇎", 588 | "lr=": "⇔", 589 | "lr~": "↭", 590 | "lrcorner": "⌟", 591 | "lr": "↔", 592 | "l-2": "⇇", 593 | "l-r-": "⇆", 594 | "l--": "⟵", 595 | "l-n": "↚", 596 | "l-|": "↤", 597 | "l->": "↢", 598 | "l-": "←", 599 | "l==": "⇚", 600 | "l=n": "⇍", 601 | "l=": "⇐", 602 | "l~": "↜", 603 | "ll-": "↞", 604 | "llcorner": "⌞", 605 | "llbracket": "〚", 606 | "ll": "≪", 607 | "lbag": "⟅", 608 | "lambda": "λ", 609 | "lamda": "λ", 610 | "lam": "λ", 611 | "lari": "₾", 612 | "langle": "⟨", 613 | "lira": "₤", 614 | "lceil": "⌈", 615 | "ldots": "…", 616 | "ldq": "“", 617 | "ldata": "《", 618 | "lfloor": "⌊", 619 | "lf": "⧏", 620 | "<|": "⧏", 621 | "lhd": "◁", 622 | "lnapprox": "⋦", 623 | "lneqq": "≨", 624 | "lneq": "≨", 625 | "lnsim": "⋦", 626 | "lnot": "¬", 627 | "longleftarrow": "⟵", 628 | "longleftrightarrow": "⟷", 629 | "longrightarrow": "⟶", 630 | "looparrowleft": "↫", 631 | "looparrowright": "↬", 632 | "lozenge": "✧", 633 | "lq": "‘", 634 | "ltimes": "⋉", 635 | "lvertneqq": "≨", 636 | "geqn": "≱", 637 | "geqq": "≧", 638 | "geqslant": "≥", 639 | "geq": "≥", 640 | "gen": "≱", 641 | "gets": "←", 642 | "ge": "≥", 643 | "glb": "⊓", 644 | "glqq": "„", 645 | "glq": "‚", 646 | "guarani": "₲", 647 | "gangia": "ϫ", 648 | "gamma": "γ", 649 | "ggg": "⋙", 650 | "gg": "≫", 651 | "gimel": "ℷ", 652 | "gnapprox": "⋧", 653 | "gneqq": "≩", 654 | "gneq": "≩", 655 | "gnsim": "⋧", 656 | "gtrapprox": "≳", 657 | "gtrdot": "⋗", 658 | "gtreqless": "⋛", 659 | "gtreqqless": "⋛", 660 | "gtrless": "≷", 661 | "gtrsim": "≳", 662 | "gvertneqq": "≩", 663 | "grqq": "“", 664 | "grq": "‘", 665 | "<=n": "≰", 666 | "<=>n": "⇎", 667 | "<=>": "⇔", 668 | "<=": "≤", 669 | "": "⋗", 675 | "<->n": "↮", 676 | "<->": "↔", 677 | "<-->": "⟷", 678 | "<--": "⟵", 679 | "<-n": "↚", 680 | "<-": "←", 681 | "<<": "⟪", 682 | ">=n": "≱", 683 | ">=": "≥", 684 | ">n": "≯", 685 | ">~nn": "≵", 686 | ">~n": "⋧", 687 | ">~": "≳", 688 | ">>": "⟫", 689 | "root": "√", 690 | "scissor": "✂", 691 | "ssubn": "⊄", 692 | "ssub": "⊂", 693 | "ssupn": "⊅", 694 | "ssup": "⊃", 695 | "ssqub": "⊏", 696 | "ssqup": "⊐", 697 | "ss": "⊆", 698 | "subn": "⊈", 699 | "subseteqq": "⊆", 700 | "subseteq": "⊆", 701 | "subsetneqq": "⊊", 702 | "subsetneq": "⊊", 703 | "subset": "⊆", 704 | "ssubset": "⊂", 705 | "sub": "⊆", 706 | "supn": "⊉", 707 | "supseteqq": "⊇", 708 | "supseteq": "⊇", 709 | "supsetneqq": "⊋", 710 | "supsetneq": "⊋", 711 | "supset": "⊇", 712 | "ssupset": "⊃", 713 | "sUnion": "⋃₀", 714 | "sInter": "⋂₀", 715 | "sup": "⊔", 716 | "supr": "⨆", 717 | "surd3": "∛", 718 | "surd4": "∜", 719 | "surd": "√", 720 | "succapprox": "≿", 721 | "succcurlyeq": "≽", 722 | "succeq": "≽", 723 | "succnapprox": "⋩", 724 | "succnsim": "⋩", 725 | "succsim": "≿", 726 | "succ": "≻", 727 | "sum": "∑", 728 | "specializes": "⤳", 729 | "~>": "⤳", 730 | "squbn": "⋢", 731 | "squb": "⊑", 732 | "squpn": "⋣", 733 | "squp": "⊒", 734 | "square": "□", 735 | "squigarrowright": "⇝", 736 | "sqb": "■", 737 | "sqw": "□", 738 | "sq.": "▣", 739 | "sqo": "▢", 740 | "sqcap": "⊓", 741 | "sqcup": "⊔", 742 | "sqrt": "√", 743 | "sqsubseteq": "⊑", 744 | "sqsubset": "⊏", 745 | "sqsupseteq": "⊒", 746 | "sqsupset": "⊐", 747 | "sq": "◾", 748 | "sy": "⁻¹", 749 | "symmdiff": "∆", 750 | "st4": "✦", 751 | "st6": "✶", 752 | "st8": "✴", 753 | "st12": "✹", 754 | "stigma": "ϛ", 755 | "star": "⋆", 756 | "straightphi": "φ", 757 | "st": "⋆", 758 | "spesmilo": "₷", 759 | "span": "∙", 760 | "spadesuit": "♠", 761 | "sphericalangle": "∢", 762 | "section": "§", 763 | "searrow": "↘", 764 | "setminus": "\\", 765 | "san": "ϻ", 766 | "sampi": "ϡ", 767 | "shortmid": "∣", 768 | "sho": "ϸ", 769 | "shima": "ϭ", 770 | "shei": "ϣ", 771 | "sharp": "♯", 772 | "sigma": "σ", 773 | "simeq": "≃", 774 | "sim": "∼", 775 | "sbs": "﹨", 776 | "smallamalg": "∐", 777 | "smallsetminus": "∖", 778 | "smallsmile": "⌣", 779 | "smile": "⌣", 780 | "smul": "•", 781 | "swarrow": "↙", 782 | "Tr": "◀", 783 | "Tb": "◀", 784 | "Tw": "◁", 785 | "Tau": "Τ", 786 | "Theta": "Θ", 787 | "TH": "Þ", 788 | "union": "∪", 789 | "undertie": "‿", 790 | "uncertainty": "⯑", 791 | "un": "∪", 792 | "u+": "⊎", 793 | "u.": "⊍", 794 | "ud-|": "↨", 795 | "ud-": "↕", 796 | "ud=": "⇕", 797 | "ud": "↕", 798 | "ul-": "↖", 799 | "ul=": "⇖", 800 | "ulcorner": "⌜", 801 | "ul": "↖", 802 | "ur-": "↗", 803 | "ur=": "⇗", 804 | "urcorner": "⌝", 805 | "ur": "↗", 806 | "u-2": "⇈", 807 | "u-d-": "⇅", 808 | "u-|": "↥", 809 | "u-": "↑", 810 | "u==": "⟰", 811 | "u=": "⇑", 812 | "uu-": "↟", 813 | "upsilon": "υ", 814 | "uparrow": "↑", 815 | "updownarrow": "↕", 816 | "upleftharpoon": "↿", 817 | "uplus": "⊎", 818 | "uprightharpoon": "↾", 819 | "upuparrows": "⇈", 820 | "And": "⋀", 821 | "AA": "Å", 822 | "AE": "Æ", 823 | "Alpha": "Α", 824 | "Or": "⋁", 825 | "O+": "⨁", 826 | "directsum": "⨁", 827 | "Ox": "⨂", 828 | "O.": "⨀", 829 | "O*": "⍟", 830 | "OE": "Œ", 831 | "Omega": "Ω", 832 | "Omicron": "Ο", 833 | "Int": "ℤ", 834 | "Inter": "⋂", 835 | "bInter": "⋂", 836 | "Iota": "Ι", 837 | "Im": "ℑ", 838 | "Un": "⋃", 839 | "Union": "⋃", 840 | "bUnion": "⋃", 841 | "U+": "⨄", 842 | "U.": "⨃", 843 | "Upsilon": "Υ", 844 | "Uparrow": "⇑", 845 | "Updownarrow": "⇕", 846 | "Gl-": "ƛ", 847 | "Gl": "λ", 848 | "Gangia": "Ϫ", 849 | "Gamma": "Γ", 850 | "Glb": "⨅", 851 | "Ga": "α", 852 | "GA": "Α", 853 | "Gb": "β", 854 | "GB": "Β", 855 | "Gg": "γ", 856 | "GG": "Γ", 857 | "Gd": "δ", 858 | "GD": "Δ", 859 | "Ge": "ε", 860 | "GE": "Ε", 861 | "Gz": "ζ", 862 | "GZ": "Ζ", 863 | "Gth": "θ", 864 | "Gt": "τ", 865 | "GTH": "Θ", 866 | "GT": "Τ", 867 | "Gi": "ι", 868 | "GI": "Ι", 869 | "Gk": "κ", 870 | "GK": "Κ", 871 | "GL": "Λ", 872 | "Gm": "μ", 873 | "GM": "Μ", 874 | "Gn": "ν", 875 | "GN": "Ν", 876 | "Gx": "ξ", 877 | "GX": "Ξ", 878 | "Gr": "ρ", 879 | "GR": "Ρ", 880 | "Gs": "σ", 881 | "GS": "Σ", 882 | "Gu": "υ", 883 | "GU": "Υ", 884 | "Gf": "φ", 885 | "GF": "Φ", 886 | "Gc": "χ", 887 | "GC": "Χ", 888 | "Gp": "ψ", 889 | "GP": "Ψ", 890 | "Go": "ω", 891 | "GO": "Ω", 892 | "Inf": "⨅", 893 | "Join": "⨆", 894 | "Lub": "⨆", 895 | "Lambda": "Λ", 896 | "Lamda": "Λ", 897 | "Leftarrow": "⇐", 898 | "Leftrightarrow": "⇔", 899 | "Letter": "✉", 900 | "Lleftarrow": "⇚", 901 | "Ll": "⋘", 902 | "Longleftarrow": "⇐", 903 | "Longleftrightarrow": "⇔", 904 | "Longrightarrow": "⇒", 905 | "Meet": "⨅", 906 | "Sup": "⨆", 907 | "Sqcap": "⨅", 908 | "Sqcup": "⨆", 909 | "Lsh": "↰", 910 | "|-n": "⊬", 911 | "|-": "⊢", 912 | "|=n": "⊭", 913 | "|=": "⊨", 914 | "|->": "↦", 915 | "|=>": "⇰", 916 | "||-n": "⊮", 917 | "||-": "⊩", 918 | "||=n": "⊯", 919 | "||=": "⊫", 920 | "|||-": "⊪", 921 | "||": "‖", 922 | "fuzzy": "‖", 923 | "|n": "∤", 924 | "Com": "ℂ", 925 | "Chi": "Χ", 926 | "Cap": "⋒", 927 | "Cup": "⋓", 928 | "cul": "⌜", 929 | "cuL": "⌈", 930 | "currency": "¤", 931 | "curlyeqprec": "⋞", 932 | "curlyeqsucc": "⋟", 933 | "curlypreceq": "≼", 934 | "curlyvee": "⋎", 935 | "curlywedge": "⋏", 936 | "curvearrowleft": "↶", 937 | "curvearrowright": "↷", 938 | "cur": "⌝", 939 | "cuR": "⌉", 940 | "cup": "∪", 941 | "cu": "⌜", 942 | "cll": "⌞", 943 | "clL": "⌊", 944 | "clr": "⌟", 945 | "clR": "⌋", 946 | "clubsuit": "♣", 947 | "cl": "⌞", 948 | "construction": "🚧", 949 | "cong": "≅", 950 | "con": "⬝", 951 | "compl": "ᶜ", 952 | "complement": "ᶜ", 953 | "complementprefix": "∁", 954 | "Complement": "∁", 955 | "comp": "∘", 956 | "com": "ℂ", 957 | "coloneq": "≔", 958 | "colon": "₡", 959 | "copyright": "©", 960 | "cdots": "⋯", 961 | "cdot": "⬝", 962 | "cib": "●", 963 | "ciw": "○", 964 | "ci..": "◌", 965 | "ci.": "◎", 966 | "ciO": "◯", 967 | "circeq": "≗", 968 | "circlearrowleft": "↺", 969 | "circlearrowright": "↻", 970 | "circledR": "®", 971 | "circledS": "Ⓢ", 972 | "circledast": "⊛", 973 | "circledcirc": "⊚", 974 | "circleddash": "⊝", 975 | "circ": "∘", 976 | "ci": "●", 977 | "centerdot": "·", 978 | "cent": "¢", 979 | "cedi": "₵", 980 | "celsius": "℃", 981 | "ce": "ȩ", 982 | "checkmark": "✓", 983 | "chi": "χ", 984 | "cruzeiro": "₢", 985 | "caution": "☡", 986 | "cap": "∩", 987 | "qed": "∎", 988 | "quad": " ", 989 | "quot": "⧸", 990 | "bigsolidus": "⧸", 991 | "/": "⧸", 992 | "+ ": "⊹", 993 | "b+": "⊞", 994 | "b-": "⊟", 995 | "bx": "⊠", 996 | "b.": "⊡", 997 | "bn": "ℕ", 998 | "bz": "ℤ", 999 | "bq": "ℚ", 1000 | "brokenbar": "¦", 1001 | "br": "ℝ", 1002 | "bc": "ℂ", 1003 | "bp": "ℙ", 1004 | "bb": "𝔹", 1005 | "bsum": "⅀", 1006 | "b0": "𝟘", 1007 | "b1": "𝟙", 1008 | "b2": "𝟚", 1009 | "b3": "𝟛", 1010 | "b4": "𝟜", 1011 | "b5": "𝟝", 1012 | "b6": "𝟞", 1013 | "b7": "𝟟", 1014 | "b8": "𝟠", 1015 | "b9": "𝟡", 1016 | "sb0": "𝟬", 1017 | "sb1": "𝟭", 1018 | "sb2": "𝟮", 1019 | "sb3": "𝟯", 1020 | "sb4": "𝟰", 1021 | "sb5": "𝟱", 1022 | "sb6": "𝟲", 1023 | "sb7": "𝟳", 1024 | "sb8": "𝟴", 1025 | "sb9": "𝟵", 1026 | "bub": "•", 1027 | "buw": "◦", 1028 | "but": "‣", 1029 | "bumpeq": "≏", 1030 | "bu": "•", 1031 | "biohazard": "☣", 1032 | "bihimp": "⇔", 1033 | "bigcap": "⋂", 1034 | "bigcirc": "◯", 1035 | "bigcoprod": "∐", 1036 | "bigcup": "⋃", 1037 | "bigglb": "⨅", 1038 | "biginf": "⨅", 1039 | "bigjoin": "⨆", 1040 | "biglub": "⨆", 1041 | "bigmeet": "⨅", 1042 | "bigsqcap": "⨅", 1043 | "bigsqcup": "⨆", 1044 | "bigstar": "★", 1045 | "bigsup": "⨆", 1046 | "bigtriangledown": "▽", 1047 | "bigtriangleup": "△", 1048 | "bigvee": "⋁", 1049 | "bigwedge": "⋀", 1050 | "beta": "β", 1051 | "beth": "ℶ", 1052 | "between": "≬", 1053 | "because": "∵", 1054 | "backcong": "≌", 1055 | "backepsilon": "∍", 1056 | "backprime": "‵", 1057 | "backsimeq": "⋍", 1058 | "backsim": "∽", 1059 | "barwedge": "⊼", 1060 | "blacklozenge": "✦", 1061 | "blacksquare": "▪", 1062 | "blacksmiley": "☻", 1063 | "blacktriangledown": "▾", 1064 | "blacktriangleleft": "◂", 1065 | "blacktriangleright": "▸", 1066 | "blacktriangle": "▴", 1067 | "bot": "⊥", 1068 | "^bot": "ᗮ", 1069 | "bowtie": "⋈", 1070 | "boxminus": "⊟", 1071 | "boxmid": "◫", 1072 | "hcomp": "◫", 1073 | "boxplus": "⊞", 1074 | "boxtimes": "⊠", 1075 | "join": "⊔", 1076 | "r-2": "⇉", 1077 | "r-3": "⇶", 1078 | "r-l-": "⇄", 1079 | "r--": "⟶", 1080 | "r-n": "↛", 1081 | "r-|": "↦", 1082 | "r->": "↣", 1083 | "r-o": "⊸", 1084 | "r-": "→", 1085 | "r==": "⇛", 1086 | "r=n": "⇏", 1087 | "r=": "⇒", 1088 | "r~": "↝", 1089 | "rr-": "↠", 1090 | "reb": "▬", 1091 | "rew": "▭", 1092 | "real": "ℝ", 1093 | "registered": "®", 1094 | "re": "▬", 1095 | "rbag": "⟆", 1096 | "rat": "ℚ", 1097 | "radioactive": "☢", 1098 | "rrbracket": "〛", 1099 | "rangle": "⟩", 1100 | "rq": "’", 1101 | "rightarrowtail": "↣", 1102 | "rightarrow": "→", 1103 | "rightharpoondown": "⇁", 1104 | "rightharpoonup": "⇀", 1105 | "rightleftarrows": "⇄", 1106 | "rightleftharpoons": "⇌", 1107 | "rightrightarrows": "⇉", 1108 | "rightthreetimes": "⋌", 1109 | "risingdotseq": "≓", 1110 | "ruble": "₽", 1111 | "rupee": "₨", 1112 | "rho": "ρ", 1113 | "rhd": "▷", 1114 | "rceil": "⌉", 1115 | "rfloor": "⌋", 1116 | "rtimes": "⋊", 1117 | "rdq": "”", 1118 | "rdata": "》", 1119 | "functor": "⥤", 1120 | "fun": "λ", 1121 | "f<<": "«", 1122 | "f>>": "»", 1123 | "f<": "‹", 1124 | "f>": "›", 1125 | "finprod": "∏ᶠ", 1126 | "finsum": "∑ᶠ", 1127 | "frac12": "½", 1128 | "frac13": "⅓", 1129 | "frac14": "¼", 1130 | "frac15": "⅕", 1131 | "frac16": "⅙", 1132 | "frac18": "⅛", 1133 | "frac1": "⅟", 1134 | "frac23": "⅔", 1135 | "frac25": "⅖", 1136 | "frac34": "¾", 1137 | "frac35": "⅗", 1138 | "frac38": "⅜", 1139 | "frac45": "⅘", 1140 | "frac56": "⅚", 1141 | "frac58": "⅝", 1142 | "frac78": "⅞", 1143 | "frac": "¼", 1144 | "frown": "⌢", 1145 | "frqq": "»", 1146 | "frq": "›", 1147 | "female": "♀", 1148 | "fei": "ϥ", 1149 | "facsimile": "℻", 1150 | "fallingdotseq": "≒", 1151 | "flat": "♭", 1152 | "flqq": "«", 1153 | "flq": "‹", 1154 | "forall": "∀", 1155 | ")b": "⟆", 1156 | "[[": "⟦", 1157 | "]]": "⟧", 1158 | "{{": "⦃", 1159 | "}}": "⦄", 1160 | "((": "⸨", 1161 | "))": "⸩", 1162 | "([": "⟮", 1163 | "])": "⟯", 1164 | "Xi": "Ξ", 1165 | "Nat": "ℕ", 1166 | "Nu": "Ν", 1167 | "Zeta": "Ζ", 1168 | "Rat": "ℚ", 1169 | "Real": "ℝ", 1170 | "Re": "ℜ", 1171 | "Rho": "Ρ", 1172 | "Rightarrow": "⇒", 1173 | "Rrightarrow": "⇛", 1174 | "Rsh": "↱", 1175 | "Fei": "Ϥ", 1176 | "Frowny": "☹", 1177 | "Hori": "Ϩ", 1178 | "Heta": "Ͱ", 1179 | "Khei": "Ϧ", 1180 | "Koppa": "Ϟ", 1181 | "Kappa": "Κ", 1182 | "^a": "ᵃ", 1183 | "^b": "ᵇ", 1184 | "^c": "ᶜ", 1185 | "^d": "ᵈ", 1186 | "^e": "ᵉ", 1187 | "^f": "ᶠ", 1188 | "^g": "ᵍ", 1189 | "^h": "ʰ", 1190 | "^i": "ⁱ", 1191 | "^j": "ʲ", 1192 | "^k": "ᵏ", 1193 | "^l": "ˡ", 1194 | "^m": "ᵐ", 1195 | "^n": "ⁿ", 1196 | "^o": "ᵒ", 1197 | "^p": "ᵖ", 1198 | "^r": "ʳ", 1199 | "^s": "ˢ", 1200 | "^t": "ᵗ", 1201 | "^u": "ᵘ", 1202 | "^v": "ᵛ", 1203 | "^w": "ʷ", 1204 | "^x": "ˣ", 1205 | "^y": "ʸ", 1206 | "^z": "ᶻ", 1207 | "^A": "ᴬ", 1208 | "^B": "ᴮ", 1209 | "^D": "ᴰ", 1210 | "^E": "ᴱ", 1211 | "^G": "ᴳ", 1212 | "^H": "ᴴ", 1213 | "^I": "ᴵ", 1214 | "^J": "ᴶ", 1215 | "^K": "ᴷ", 1216 | "^L": "ᴸ", 1217 | "^M": "ᴹ", 1218 | "^N": "ᴺ", 1219 | "^O": "ᴼ", 1220 | "^P": "ᴾ", 1221 | "^R": "ᴿ", 1222 | "^T": "ᵀ", 1223 | "^U": "ᵁ", 1224 | "^V": "ⱽ", 1225 | "^W": "ᵂ", 1226 | "^0": "⁰", 1227 | "^1": "¹", 1228 | "^2": "²", 1229 | "^3": "³", 1230 | "^4": "⁴", 1231 | "^5": "⁵", 1232 | "^6": "⁶", 1233 | "^7": "⁷", 1234 | "^8": "⁸", 1235 | "^9": "⁹", 1236 | "^)": "⁾", 1237 | "^(": "⁽", 1238 | "^=": "⁼", 1239 | "^+": "⁺", 1240 | "^o_": "º", 1241 | "^-": "⁻", 1242 | "^a_": "ª", 1243 | "^uhook": "ꭟ", 1244 | "^ubar": "ᶶ", 1245 | "^upsilon": "ᶷ", 1246 | "^ltilde": "ꭞ", 1247 | "^ls": "ꭝ", 1248 | "^lhook": "ᶪ", 1249 | "^lretroflexhook": "ᶩ", 1250 | "^oe": "ꟹ", 1251 | "^heng": "ꭜ", 1252 | "^hhook": "ʱ", 1253 | "^hwithhook": "ʱ", 1254 | "^Hstroke": "ꟸ", 1255 | "^theta": "ᶿ", 1256 | "^turnedv": "ᶺ", 1257 | "^turnedmleg": "ᶭ", 1258 | "^turnedm": "ᵚ", 1259 | "^turnedh": "ᶣ", 1260 | "^turnedalpha": "ᶛ", 1261 | "^turnedae": "ᵆ", 1262 | "^turneda": "ᵄ", 1263 | "^turnedi": "ᵎ", 1264 | "^turnede": "ᵌ", 1265 | "^turnedrhook": "ʵ", 1266 | "^turnedrwithhook": "ʵ", 1267 | "^turnedr": "ʴ", 1268 | "^twithpalatalhook": "ᶵ", 1269 | "^otop": "ᵔ", 1270 | "^ezh": "ᶾ", 1271 | "^esh": "ᶴ", 1272 | "^eth": "ᶞ", 1273 | "^eng": "ᵑ", 1274 | "^zcurl": "ᶽ", 1275 | "^zretroflexhook": "ᶼ", 1276 | "^vhook": "ᶹ", 1277 | "^Ismall": "ᶦ", 1278 | "^Lsmall": "ᶫ", 1279 | "^Nsmall": "ᶰ", 1280 | "^Usmall": "ᶸ", 1281 | "^Istroke": "ᶧ", 1282 | "^Rinverted": "ʶ", 1283 | "^ccurl": "ᶝ", 1284 | "^chi": "ᵡ", 1285 | "^shook": "ᶳ", 1286 | "^gscript": "ᶢ", 1287 | "^schwa": "ᵊ", 1288 | "^usideways": "ᵙ", 1289 | "^phi": "ᶲ", 1290 | "^obarred": "ᶱ", 1291 | "^beta": "ᵝ", 1292 | "^obottom": "ᵕ", 1293 | "^nretroflexhook": "ᶯ", 1294 | "^nlefthook": "ᶮ", 1295 | "^mhook": "ᶬ", 1296 | "^jtail": "ᶨ", 1297 | "^iota": "ᶥ", 1298 | "^istroke": "ᶤ", 1299 | "^ereversedopen": "ᶟ", 1300 | "^stop": "ˤ", 1301 | "^varphi": "ᵠ", 1302 | "^vargamma": "ᵞ", 1303 | "^gamma": "ˠ", 1304 | "^ain": "ᵜ", 1305 | "^alpha": "ᵅ", 1306 | "^oopen": "ᵓ", 1307 | "^eopen": "ᵋ", 1308 | "^Ou": "ᴽ", 1309 | "^Nreversed": "ᴻ", 1310 | "^Ereversed": "ᴲ", 1311 | "^Bbarred": "ᴯ", 1312 | "^Ae": "ᴭ", 1313 | "^SM": "℠", 1314 | "^TEL": "℡", 1315 | "^TM": "™", 1316 | "_a": "ₐ", 1317 | "_e": "ₑ", 1318 | "_h": "ₕ", 1319 | "_i": "ᵢ", 1320 | "_j": "ⱼ", 1321 | "_k": "ₖ", 1322 | "_l": "ₗ", 1323 | "_m": "ₘ", 1324 | "_n": "ₙ", 1325 | "_o": "ₒ", 1326 | "_p": "ₚ", 1327 | "_r": "ᵣ", 1328 | "_s": "ₛ", 1329 | "_t": "ₜ", 1330 | "_u": "ᵤ", 1331 | "_v": "ᵥ", 1332 | "_x": "ₓ", 1333 | "_0": "₀", 1334 | "_1": "₁", 1335 | "_2": "₂", 1336 | "_3": "₃", 1337 | "_4": "₄", 1338 | "_5": "₅", 1339 | "_6": "₆", 1340 | "_7": "₇", 1341 | "_8": "₈", 1342 | "_9": "₉", 1343 | "_)": "₎", 1344 | "_(": "₍", 1345 | "_=": "₌", 1346 | "_+": "₊", 1347 | "_--": "̲", 1348 | "_-": "₋", 1349 | "!!": "‼", 1350 | "!?": "⁉", 1351 | "San": "Ϻ", 1352 | "Sampi": "Ϡ", 1353 | "Sho": "Ϸ", 1354 | "Shima": "Ϭ", 1355 | "Shei": "Ϣ", 1356 | "Stigma": "Ϛ", 1357 | "Sigma": "Σ", 1358 | "Subset": "⋐", 1359 | "Supset": "⋑", 1360 | "Smiley": "☺", 1361 | "Psi": "Ψ", 1362 | "Phi": "Φ", 1363 | "Pi": "Π", 1364 | "Pi0": "Π₀", 1365 | "P0": "Π₀", 1366 | "Pi_0": "Π₀", 1367 | "P_0": "Π₀", 1368 | "bfA": "𝐀", 1369 | "bfB": "𝐁", 1370 | "bfC": "𝐂", 1371 | "bfD": "𝐃", 1372 | "bfE": "𝐄", 1373 | "bfF": "𝐅", 1374 | "bfG": "𝐆", 1375 | "bfH": "𝐇", 1376 | "bfI": "𝐈", 1377 | "bfJ": "𝐉", 1378 | "bfK": "𝐊", 1379 | "bfL": "𝐋", 1380 | "bfM": "𝐌", 1381 | "bfN": "𝐍", 1382 | "bfO": "𝐎", 1383 | "bfP": "𝐏", 1384 | "bfQ": "𝐐", 1385 | "bfR": "𝐑", 1386 | "bfS": "𝐒", 1387 | "bfT": "𝐓", 1388 | "bfU": "𝐔", 1389 | "bfV": "𝐕", 1390 | "bfW": "𝐖", 1391 | "bfX": "𝐗", 1392 | "bfY": "𝐘", 1393 | "bfZ": "𝐙", 1394 | "bfa": "𝐚", 1395 | "bfb": "𝐛", 1396 | "bfc": "𝐜", 1397 | "bfd": "𝐝", 1398 | "bfe": "𝐞", 1399 | "bff": "𝐟", 1400 | "bfg": "𝐠", 1401 | "bfh": "𝐡", 1402 | "bfi": "𝐢", 1403 | "bfj": "𝐣", 1404 | "bfk": "𝐤", 1405 | "bfl": "𝐥", 1406 | "bfm": "𝐦", 1407 | "bfn": "𝐧", 1408 | "bfo": "𝐨", 1409 | "bfp": "𝐩", 1410 | "bfq": "𝐪", 1411 | "bfr": "𝐫", 1412 | "bfs": "𝐬", 1413 | "bft": "𝐭", 1414 | "bfu": "𝐮", 1415 | "bfv": "𝐯", 1416 | "bfw": "𝐰", 1417 | "bfx": "𝐱", 1418 | "bfy": "𝐲", 1419 | "bfz": "𝐳", 1420 | "MiA": "𝐴", 1421 | "MiB": "𝐵", 1422 | "MiC": "𝐶", 1423 | "MiD": "𝐷", 1424 | "MiE": "𝐸", 1425 | "MiF": "𝐹", 1426 | "MiG": "𝐺", 1427 | "MiH": "𝐻", 1428 | "MiI": "𝐼", 1429 | "MiJ": "𝐽", 1430 | "MiK": "𝐾", 1431 | "MiL": "𝐿", 1432 | "MiM": "𝑀", 1433 | "MiN": "𝑁", 1434 | "MiO": "𝑂", 1435 | "MiP": "𝑃", 1436 | "MiQ": "𝑄", 1437 | "MiR": "𝑅", 1438 | "MiS": "𝑆", 1439 | "MiT": "𝑇", 1440 | "MiU": "𝑈", 1441 | "MiV": "𝑉", 1442 | "MiW": "𝑊", 1443 | "MiX": "𝑋", 1444 | "MiY": "𝑌", 1445 | "MiZ": "𝑍", 1446 | "Mia": "𝑎", 1447 | "Mib": "𝑏", 1448 | "Mic": "𝑐", 1449 | "Mid": "𝑑", 1450 | "Mie": "𝑒", 1451 | "Mif": "𝑓", 1452 | "Mig": "𝑔", 1453 | "Mii": "𝑖", 1454 | "Mij": "𝑗", 1455 | "Mik": "𝑘", 1456 | "Mil": "𝑙", 1457 | "Mim": "𝑚", 1458 | "Min": "𝑛", 1459 | "Mio": "𝑜", 1460 | "Mip": "𝑝", 1461 | "Miq": "𝑞", 1462 | "Mir": "𝑟", 1463 | "Mis": "𝑠", 1464 | "Mit": "𝑡", 1465 | "Miu": "𝑢", 1466 | "Miv": "𝑣", 1467 | "Miw": "𝑤", 1468 | "Mix": "𝑥", 1469 | "Miy": "𝑦", 1470 | "Miz": "𝑧", 1471 | "MIA": "𝑨", 1472 | "MIB": "𝑩", 1473 | "MIC": "𝑪", 1474 | "MID": "𝑫", 1475 | "MIE": "𝑬", 1476 | "MIF": "𝑭", 1477 | "MIG": "𝑮", 1478 | "MIH": "𝑯", 1479 | "MII": "𝑰", 1480 | "MIJ": "𝑱", 1481 | "MIK": "𝑲", 1482 | "MIL": "𝑳", 1483 | "MIM": "𝑴", 1484 | "MIN": "𝑵", 1485 | "MIO": "𝑶", 1486 | "MIP": "𝑷", 1487 | "MIQ": "𝑸", 1488 | "MIR": "𝑹", 1489 | "MIS": "𝑺", 1490 | "MIT": "𝑻", 1491 | "MIU": "𝑼", 1492 | "MIV": "𝑽", 1493 | "MIW": "𝑾", 1494 | "MIX": "𝑿", 1495 | "MIY": "𝒀", 1496 | "MIZ": "𝒁", 1497 | "MIa": "𝒂", 1498 | "MIb": "𝒃", 1499 | "MIc": "𝒄", 1500 | "MId": "𝒅", 1501 | "MIe": "𝒆", 1502 | "MIf": "𝒇", 1503 | "MIg": "𝒈", 1504 | "MIh": "𝒉", 1505 | "MIi": "𝒊", 1506 | "MIj": "𝒋", 1507 | "MIk": "𝒌", 1508 | "MIl": "𝒍", 1509 | "MIm": "𝒎", 1510 | "MIn": "𝒏", 1511 | "MIo": "𝒐", 1512 | "MIp": "𝒑", 1513 | "MIq": "𝒒", 1514 | "MIr": "𝒓", 1515 | "MIs": "𝒔", 1516 | "MIt": "𝒕", 1517 | "MIu": "𝒖", 1518 | "MIv": "𝒗", 1519 | "MIw": "𝒘", 1520 | "MIx": "𝒙", 1521 | "MIy": "𝒚", 1522 | "MIz": "𝒛", 1523 | "McA": "𝒜", 1524 | "McB": "ℬ", 1525 | "McC": "𝒞", 1526 | "McD": "𝒟", 1527 | "McE": "ℰ", 1528 | "McF": "ℱ", 1529 | "McG": "𝒢", 1530 | "McH": "ℋ", 1531 | "McI": "ℐ", 1532 | "McJ": "𝒥", 1533 | "McK": "𝒦", 1534 | "McL": "ℒ", 1535 | "McM": "ℳ", 1536 | "McN": "𝒩", 1537 | "McO": "𝒪", 1538 | "McP": "𝒫", 1539 | "McQ": "𝒬", 1540 | "McR": "ℛ", 1541 | "McS": "𝒮", 1542 | "McT": "𝒯", 1543 | "McU": "𝒰", 1544 | "McV": "𝒱", 1545 | "McW": "𝒲", 1546 | "McX": "𝒳", 1547 | "McY": "𝒴", 1548 | "McZ": "𝒵", 1549 | "Mca": "𝒶", 1550 | "Mcb": "𝒷", 1551 | "Mcc": "𝒸", 1552 | "Mcd": "𝒹", 1553 | "Mce": "ℯ", 1554 | "Mcf": "𝒻", 1555 | "Mcg": "ℊ", 1556 | "Mch": "𝒽", 1557 | "Mci": "𝒾", 1558 | "Mcj": "𝒿", 1559 | "Mck": "𝓀", 1560 | "Mcl": "𝓁", 1561 | "Mcm": "𝓂", 1562 | "Mcn": "𝓃", 1563 | "Mco": "ℴ", 1564 | "Mcp": "𝓅", 1565 | "Mcq": "𝓆", 1566 | "Mcr": "𝓇", 1567 | "Mcs": "𝓈", 1568 | "Mct": "𝓉", 1569 | "Mcu": "𝓊", 1570 | "Mcv": "𝓋", 1571 | "Mcw": "𝓌", 1572 | "Mcx": "𝓍", 1573 | "Mcy": "𝓎", 1574 | "Mcz": "𝓏", 1575 | "MCA": "𝓐", 1576 | "MCB": "𝓑", 1577 | "MCC": "𝓒", 1578 | "MCD": "𝓓", 1579 | "MCE": "𝓔", 1580 | "MCF": "𝓕", 1581 | "MCG": "𝓖", 1582 | "MCH": "𝓗", 1583 | "MCI": "𝓘", 1584 | "MCJ": "𝓙", 1585 | "MCK": "𝓚", 1586 | "MCL": "𝓛", 1587 | "MCM": "𝓜", 1588 | "MCN": "𝓝", 1589 | "MCO": "𝓞", 1590 | "MCP": "𝓟", 1591 | "MCQ": "𝓠", 1592 | "MCR": "𝓡", 1593 | "MCS": "𝓢", 1594 | "MCT": "𝓣", 1595 | "MCU": "𝓤", 1596 | "MCV": "𝓥", 1597 | "MCW": "𝓦", 1598 | "MCX": "𝓧", 1599 | "MCY": "𝓨", 1600 | "MCZ": "𝓩", 1601 | "MCa": "𝓪", 1602 | "MCb": "𝓫", 1603 | "MCc": "𝓬", 1604 | "MCd": "𝓭", 1605 | "MCe": "𝓮", 1606 | "MCf": "𝓯", 1607 | "MCg": "𝓰", 1608 | "MCh": "𝓱", 1609 | "MCi": "𝓲", 1610 | "MCj": "𝓳", 1611 | "MCk": "𝓴", 1612 | "MCl": "𝓵", 1613 | "MCm": "𝓶", 1614 | "MCn": "𝓷", 1615 | "MCo": "𝓸", 1616 | "MCp": "𝓹", 1617 | "MCq": "𝓺", 1618 | "MCr": "𝓻", 1619 | "MCs": "𝓼", 1620 | "MCt": "𝓽", 1621 | "MCu": "𝓾", 1622 | "MCv": "𝓿", 1623 | "MCw": "𝔀", 1624 | "MCx": "𝔁", 1625 | "MCy": "𝔂", 1626 | "MCz": "𝔃", 1627 | "MfA": "𝔄", 1628 | "MfB": "𝔅", 1629 | "MfC": "ℭ", 1630 | "MfD": "𝔇", 1631 | "MfE": "𝔈", 1632 | "MfF": "𝔉", 1633 | "MfG": "𝔊", 1634 | "MfH": "ℌ", 1635 | "MfI": "ℑ", 1636 | "MfJ": "𝔍", 1637 | "MfK": "𝔎", 1638 | "MfL": "𝔏", 1639 | "MfM": "𝔐", 1640 | "MfN": "𝔑", 1641 | "MfO": "𝔒", 1642 | "MfP": "𝔓", 1643 | "MfQ": "𝔔", 1644 | "MfR": "ℜ", 1645 | "MfS": "𝔖", 1646 | "MfT": "𝔗", 1647 | "MfU": "𝔘", 1648 | "MfV": "𝔙", 1649 | "MfW": "𝔚", 1650 | "MfX": "𝔛", 1651 | "MfY": "𝔜", 1652 | "MfZ": "ℨ", 1653 | "Mfa": "𝔞", 1654 | "Mfb": "𝔟", 1655 | "Mfc": "𝔠", 1656 | "Mfd": "𝔡", 1657 | "Mfe": "𝔢", 1658 | "Mff": "𝔣", 1659 | "Mfg": "𝔤", 1660 | "Mfh": "𝔥", 1661 | "Mfi": "𝔦", 1662 | "Mfj": "𝔧", 1663 | "Mfk": "𝔨", 1664 | "Mfl": "𝔩", 1665 | "Mfm": "𝔪", 1666 | "Mfn": "𝔫", 1667 | "Mfo": "𝔬", 1668 | "Mfp": "𝔭", 1669 | "Mfq": "𝔮", 1670 | "Mfr": "𝔯", 1671 | "Mfs": "𝔰", 1672 | "Mft": "𝔱", 1673 | "Mfu": "𝔲", 1674 | "Mfv": "𝔳", 1675 | "Mfw": "𝔴", 1676 | "Mfx": "𝔵", 1677 | "Mfy": "𝔶", 1678 | "Mfz": "𝔷", 1679 | "yen": "¥", 1680 | "varrho": "ϱ", 1681 | "varkappa": "ϰ", 1682 | "varkai": "ϗ", 1683 | "varnothing": "∅", 1684 | "varpi": "ϖ", 1685 | "varphi": "ϕ", 1686 | "varprime": "′", 1687 | "varpropto": "∝", 1688 | "vartheta": "ϑ", 1689 | "vartriangleleft": "⊲", 1690 | "vartriangleright": "⊳", 1691 | "varbeta": "ϐ", 1692 | "varsigma": "ς", 1693 | "veebar": "⊻", 1694 | "vee": "∨", 1695 | "ve": "ě", 1696 | "vE": "Ě", 1697 | "vdash": "⊢", 1698 | "vdots": "⋮", 1699 | "vd": "ď", 1700 | "vDash": "⊨", 1701 | "vD": "Ď", 1702 | "vc": "č", 1703 | "vC": "Č", 1704 | "koppa": "ϟ", 1705 | "kip": "₭", 1706 | "ki": "į", 1707 | "kI": "Į", 1708 | "kelvin": "K", 1709 | "kappa": "κ", 1710 | "khei": "ϧ", 1711 | "warning": "⚠", 1712 | "won": "₩", 1713 | "wedge": "∧", 1714 | "wp": "℘", 1715 | "wr": "≀", 1716 | "Dei": "Ϯ", 1717 | "Delta": "Δ", 1718 | "Digamma": "Ϝ", 1719 | "Diamond": "◇", 1720 | "Downarrow": "⇓", 1721 | "DH": "Ð", 1722 | "zeta": "ζ", 1723 | "Eta": "Η", 1724 | "Epsilon": "Ε", 1725 | "Beta": "Β", 1726 | "Box": "□", 1727 | "Bumpeq": "≎", 1728 | "bbA": "𝔸", 1729 | "bbB": "𝔹", 1730 | "bbC": "ℂ", 1731 | "bbD": "𝔻", 1732 | "bbE": "𝔼", 1733 | "bbF": "𝔽", 1734 | "bbG": "𝔾", 1735 | "bbH": "ℍ", 1736 | "bbI": "𝕀", 1737 | "bbJ": "𝕁", 1738 | "bbK": "𝕂", 1739 | "bbL": "𝕃", 1740 | "bbM": "𝕄", 1741 | "bbN": "ℕ", 1742 | "bbO": "𝕆", 1743 | "bbP": "ℙ", 1744 | "bbQ": "ℚ", 1745 | "bbR": "ℝ", 1746 | "bbS": "𝕊", 1747 | "bbT": "𝕋", 1748 | "bbU": "𝕌", 1749 | "bbV": "𝕍", 1750 | "bbW": "𝕎", 1751 | "bbX": "𝕏", 1752 | "bbY": "𝕐", 1753 | "bbZ": "ℤ", 1754 | "bba": "𝕒", 1755 | "bbb": "𝕓", 1756 | "bbc": "𝕔", 1757 | "bbd": "𝕕", 1758 | "bbe": "𝕖", 1759 | "bbf": "𝕗", 1760 | "bbg": "𝕘", 1761 | "bbh": "𝕙", 1762 | "bbi": "𝕚", 1763 | "bbj": "𝕛", 1764 | "bbk": "𝕜", 1765 | "bbl": "𝕝", 1766 | "bbm": "𝕞", 1767 | "bbn": "𝕟", 1768 | "bbo": "𝕠", 1769 | "bbp": "𝕡", 1770 | "bbq": "𝕢", 1771 | "bbr": "𝕣", 1772 | "bbs": "𝕤", 1773 | "bbt": "𝕥", 1774 | "bbu": "𝕦", 1775 | "bbv": "𝕧", 1776 | "bbw": "𝕨", 1777 | "bbx": "𝕩", 1778 | "bby": "𝕪", 1779 | "bbz": "𝕫", 1780 | "Rge0": "ℝ≥0", 1781 | "R>=0": "ℝ≥0", 1782 | "nnreal": "ℝ≥0", 1783 | "ennreal": "ℝ≥0∞", 1784 | "enat": "ℕ∞", 1785 | "Zsqrt": "ℤ√", 1786 | "zsqrtd": "ℤ√", 1787 | "liel": "⁅", 1788 | "bracketl": "⁅", 1789 | "lier": "⁆", 1790 | "[-": "⁅", 1791 | "-]": "⁆", 1792 | "lsimplex": "⦋", 1793 | "rsimplex": "⦌", 1794 | "bracketr": "⁆", 1795 | "nhds": "𝓝", 1796 | "nbhds": "𝓝", 1797 | "X": "⨯", 1798 | "vectorproduct": "⨯", 1799 | "crossproduct": "⨯", 1800 | "xs": "×ˢ", 1801 | "coprod": "⨿", 1802 | "sigmaobj": "∐", 1803 | "xf": "×ᶠ", 1804 | "exf": "∃ᶠ", 1805 | "c[": "⦃", 1806 | "c]": "⦄", 1807 | "Yot": "Ϳ", 1808 | "goal": "⊢", 1809 | "Vdash": "⊩", 1810 | "Vert": "‖", 1811 | "Vvdash": "⊪", 1812 | "tiny": "⧾", 1813 | "miny": "⧿" 1814 | } 1815 | -------------------------------------------------------------------------------- /lean4-eri.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-eri.el --- Lean4-Mode Indentation -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2005-2010 Ulf Norell, Nils Anders Danielsson, 4 | ;; Catarina Coquand, Makoto Takeyama, Andreas Abel, Karl Mehltretter, 5 | ;; Marcin Benke, Darin Morrison. 6 | 7 | ;; This file is not part of GNU Emacs. 8 | 9 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 10 | ;; may not use this file except in compliance with the License. You 11 | ;; may obtain a copy of the License at 12 | ;; 13 | ;; http://www.apache.org/licenses/LICENSE-2.0 14 | ;; 15 | ;; Unless required by applicable law or agreed to in writing, software 16 | ;; distributed under the License is distributed on an "AS IS" BASIS, 17 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 18 | ;; implied. See the License for the specific language governing 19 | ;; permissions and limitations under the License. 20 | 21 | ;;; Commentary: 22 | 23 | ;; This file is based on eri.el which was part of Agda-Mode: 24 | ;; https://github.com/agda/agda/blob/b40c6fc2e0ced7b547553654f81e5898082d700c/src/data/emacs-mode/eri.el 25 | 26 | ;;; Code: 27 | 28 | (require 'cl-lib) 29 | 30 | (defun lean4-eri-current-line-length nil 31 | "Calculate length of current line." 32 | (- (line-end-position) (line-beginning-position))) 33 | 34 | (defun lean4-eri-current-line-empty nil 35 | "Return non-nil if the current line is empty (not counting white space)." 36 | (equal (current-indentation) 37 | (lean4-eri-current-line-length))) 38 | 39 | (defun lean4-eri-maximum (xs) 40 | "Calculate maximum element in XS. 41 | Returns nil if the list is empty." 42 | (if xs (apply #'max xs))) 43 | 44 | (defun lean4-eri-take (n xs) 45 | "Return the first N elements of XS." 46 | (butlast xs (- (length xs) n))) 47 | 48 | (defun lean4-eri-split (x xs) 49 | "Return a pair of lists (XS1 . XS2). 50 | If XS is sorted, then XS = (append XS1 XS2), and all elements in 51 | XS1 are <= X, whereas all elements in XS2 are > X." 52 | (let* ((pos (or (cl-position-if (lambda (y) (> y x)) xs) (length xs))) 53 | (xs1 (lean4-eri-take pos xs)) 54 | (xs2 (nthcdr pos xs))) 55 | (cons xs1 xs2))) 56 | 57 | (defun lean4-eri-calculate-indentation-points-on-line (max) 58 | "Calculate indentation points on current line. 59 | Only points left of column number MAX are included. If MAX is 60 | nil, then all points are included. Points are returned in 61 | ascending order. 62 | 63 | Example (positions marked with ^ are returned): 64 | 65 | f x y = g 3 (Just y) 5 4 66 | ^ ^ ^ ^ ^ ^ ^ ^ | 67 | | 68 | MAX" 69 | (let ((result)) 70 | (save-excursion 71 | (save-restriction 72 | (beginning-of-line) 73 | ; To make \\` work in the regexp below: 74 | (narrow-to-region (line-beginning-position) (line-end-position)) 75 | (while 76 | (progn 77 | (let ((pos (and (search-forward-regexp 78 | "\\(?:\\s-\\|\\`\\)\\(\\S-\\)" nil t) 79 | (match-beginning 1)))) 80 | (when pos 81 | (let ((pos1 (- pos (line-beginning-position)))) 82 | (when (or (null max) (< pos1 max)) 83 | (cl-pushnew pos1 result)))) 84 | (and pos 85 | (not (eolp)) 86 | (or (null max) (< (current-column) max)))))) 87 | (nreverse result) ; Destructive operation. 88 | )))) 89 | 90 | (defun lean4-eri-new-indentation-points () 91 | "Calculate new indentation points. 92 | Returns a singleton list containing the column number two steps 93 | in from the indentation of the first non-empty line (white space 94 | excluded) above the current line. If there is no such line, 95 | then the empty list is returned." 96 | (let ((start (line-beginning-position))) 97 | (save-excursion 98 | ; Find a non-empty line above the current one, if any. 99 | (while 100 | (progn 101 | (forward-line -1) 102 | (not (or (bobp) 103 | (not (lean4-eri-current-line-empty)))))) 104 | (if (or (equal (point) start) 105 | (lean4-eri-current-line-empty)) 106 | nil 107 | (list (+ 2 (current-indentation))))))) 108 | 109 | (defun lean4-eri-calculate-indentation-points (reverse) 110 | "Calculate points used to indent the current line. 111 | The points are given in reverse order if REVERSE is non-nil. See 112 | `lean4-eri-indent' for a description of how the indentation points are 113 | calculated; note that the current indentation is not included in 114 | the returned list." 115 | ;; First find a bunch of indentations used above the current line. 116 | (let ((points) 117 | (max) 118 | (start (line-beginning-position))) 119 | (save-excursion 120 | (while 121 | (progn 122 | (forward-line -1) 123 | ; Skip the line we started from and lines with nothing but 124 | ; white space. 125 | (unless (or (equal (point) start) 126 | (lean4-eri-current-line-empty)) 127 | (setq points 128 | (append 129 | (lean4-eri-calculate-indentation-points-on-line max) 130 | points)) 131 | (setq max (car points))) 132 | ;; Stop after hitting the beginning of the buffer or a 133 | ;; non-empty, non-indented line. 134 | (not (or (bobp) 135 | (and (equal (current-indentation) 0) 136 | (> (lean4-eri-current-line-length) 0))))))) 137 | ;; Add new indentation points, but remove the current indentation. 138 | ;; Sort the indentations. Rearrange the points so that the next 139 | ;; point is the one after the current one. Reverse if necessary. 140 | ;; 141 | ;; Note: sort and nreverse are destructive. 142 | (let* ((ps0 (remove (current-indentation) 143 | (append (lean4-eri-new-indentation-points) points))) 144 | (ps1 (lean4-eri-split (current-indentation) (sort ps0 '<))) 145 | (ps2 (append (cdr ps1) (car ps1)))) 146 | (if reverse 147 | (nreverse ps2) 148 | ps2)))) 149 | 150 | (defun lean4-eri-indent (&optional reverse) 151 | "Cycle between some possible indentation points. 152 | With prefix argument REVERSE, cycle in reverse order. 153 | 154 | Assume that a file contains the following lines of code, with 155 | point on the line with three dots: 156 | 157 | frob = loooooooooooooooooooooooooong identifier 158 | foo = f a b 159 | where 160 | f (Foo x) y = let bar = x 161 | baz = 3 + 5 162 | 163 | ... 164 | 165 | ^ ^ ^ ^ ^ ^ ^ ^ ^ * ^ ^ ^ ^ 166 | 167 | Then the ^'s and the * mark the indentation points that this 168 | function cycles through. The indentation points are selected as 169 | follows: 170 | 171 | * All lines before the current one, up to and including the 172 | first non-indented line (or the beginning of the buffer) are 173 | considered. 174 | 175 | foo = f a b 176 | where 177 | f (Foo x) y = let bar = x 178 | baz = 3 + 5 179 | 180 | * On these lines, erase all characters that stand to the right 181 | of some non-white space character on a lower line. 182 | 183 | foo 184 | whe 185 | f (Foo x) y = let b 186 | baz = 3 + 5 187 | 188 | * Also erase all characters not immediately preceded by white 189 | space. 190 | 191 | f 192 | w 193 | f ( x y = l b 194 | b = 3 + 5 195 | 196 | * The columns of all remaining characters are indentation 197 | points. 198 | 199 | f w f ( x y = l b = 3 + 5 200 | ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 201 | 202 | * A new indentation point is also added, two steps in from the 203 | indentation of the first non-empty line (white space 204 | excluded) above the current line (if there is such a line). 205 | 206 | f w f ( x y = l b = 3 + 5 207 | ^ ^ ^ ^ ^ ^ ^ ^ ^ * ^ ^ ^ ^" 208 | (interactive "P") 209 | (let* ((points (lean4-eri-calculate-indentation-points reverse)) 210 | (remaining-points (cdr (member (current-indentation) points))) 211 | (indentation (if remaining-points 212 | (car remaining-points) 213 | (car points)))) 214 | (when indentation 215 | (save-excursion (indent-line-to indentation)) 216 | (if (< (current-column) indentation) 217 | (indent-line-to indentation))))) 218 | 219 | (defun lean4-eri-indent-reverse nil 220 | "Cycle between some possible indentation points (in reverse order). 221 | See `lean4-eri-indent' for a description of how the indentation points 222 | are calculated." 223 | (interactive) 224 | (lean4-eri-indent t)) 225 | 226 | (provide 'lean4-eri) 227 | ;;; lean4-eri.el ends here 228 | -------------------------------------------------------------------------------- /lean4-fringe.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-fringe.el --- Lean4-Mode Processing Progress in Fringe -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2016 Microsoft Corporation. All rights reserved. 4 | 5 | ;; This file is not part of GNU Emacs. 6 | 7 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 8 | ;; may not use this file except in compliance with the License. You 9 | ;; may obtain a copy of the License at 10 | ;; 11 | ;; http://www.apache.org/licenses/LICENSE-2.0 12 | ;; 13 | ;; Unless required by applicable law or agreed to in writing, software 14 | ;; distributed under the License is distributed on an "AS IS" BASIS, 15 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 16 | ;; implied. See the License for the specific language governing 17 | ;; permissions and limitations under the License. 18 | 19 | ;;; Commentary: 20 | 21 | ;; Show Lean processing progress in the editor fringe 22 | 23 | ;;; Code: 24 | 25 | (require 'lean4-settings) 26 | (require 'lsp-mode) 27 | (require 'lsp-protocol) 28 | 29 | (eval-and-compile 30 | (lsp-interface 31 | (lean:LeanFileProgressProcessingInfo (:range :kind) nil) 32 | (lean:LeanFileProgressParams (:textDocument :processing) nil))) 33 | 34 | (defvar-local lean4-fringe-delay-timer nil) 35 | 36 | (lsp-defun lean4-fringe-region ((&lean:LeanFileProgressProcessingInfo :range)) 37 | (lsp--range-to-region range)) 38 | 39 | (defface lean4-fringe-face 40 | nil 41 | "Face to highlight Lean file progress." 42 | :group 'lean4) 43 | 44 | (if (fboundp 'define-fringe-bitmap) 45 | (define-fringe-bitmap 'lean4-fringe-fringe-bitmap 46 | (vector) 16 8)) 47 | 48 | (defface lean4-fringe-fringe-processing-face 49 | '((((class color) (background light)) 50 | :background "chocolate1") 51 | (((class color) (background dark)) 52 | :background "navajo white") 53 | (t :inverse-video t)) 54 | "Face to highlight the fringe of Lean file processing progress." 55 | :group 'lean4) 56 | 57 | (defface lean4-fringe-fringe-fatal-error-face 58 | '((((class color) (background light)) 59 | :background "red") 60 | (((class color) (background dark)) 61 | :background "red") 62 | (t :inverse-video t)) 63 | "Face to highlight the fringe of Lean file fatal errors." 64 | :group 'lean4) 65 | 66 | (lsp-defun lean4-fringe-fringe-face ((&lean:LeanFileProgressProcessingInfo :kind)) 67 | (cond 68 | ((eq kind 1) 'lean4-fringe-fringe-processing-face) 69 | (t 'lean4-fringe-fringe-fatal-error-face))) 70 | 71 | (defvar-local lean4-fringe-data nil) 72 | 73 | (defun lean4-fringe-update-progress-overlays () 74 | "Update processing bars in the current buffer." 75 | (dolist (ov (flatten-tree (overlay-lists))) 76 | (when (eq (overlay-get ov 'face) 'lean4-fringe-face) 77 | (delete-overlay ov))) 78 | (when lean4-show-file-progress 79 | (seq-doseq (item lean4-fringe-data) 80 | (let* ((reg (lean4-fringe-region item)) 81 | (ov (make-overlay (car reg) (cdr reg)))) 82 | (overlay-put ov 'face 'lean4-fringe-face) 83 | (overlay-put ov 'line-prefix 84 | (propertize " " 'display 85 | `(left-fringe lean4-fringe-fringe-bitmap ,(lean4-fringe-fringe-face item)))) 86 | (overlay-put ov 'help-echo (format "processing...")))))) 87 | 88 | (defvar-local lean4-fringe-delay-timer nil) 89 | 90 | (lsp-defun lean4-fringe-update (workspace (&lean:LeanFileProgressParams :processing :text-document (&VersionedTextDocumentIdentifier :uri))) 91 | (dolist (buf (lsp--workspace-buffers workspace)) 92 | (lsp-with-current-buffer buf 93 | (when (equal (lsp--buffer-uri) uri) 94 | (setq lean4-fringe-data processing) 95 | (save-match-data 96 | (when (not (memq lean4-fringe-delay-timer timer-list)) 97 | (setq lean4-fringe-delay-timer 98 | (run-at-time "300 milliseconds" nil 99 | (lambda (buf) 100 | (with-current-buffer buf 101 | (lean4-fringe-update-progress-overlays))) 102 | (current-buffer))))))))) 103 | 104 | (provide 'lean4-fringe) 105 | ;;; lean4-fringe.el ends here 106 | -------------------------------------------------------------------------------- /lean4-info.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-info.el --- Lean4-Mode Info View -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2016 Gabriel Ebner. All rights reserved. 4 | 5 | ;; This file is not part of GNU Emacs. 6 | 7 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 8 | ;; may not use this file except in compliance with the License. You 9 | ;; may obtain a copy of the License at 10 | ;; 11 | ;; http://www.apache.org/licenses/LICENSE-2.0 12 | ;; 13 | ;; Unless required by applicable law or agreed to in writing, software 14 | ;; distributed under the License is distributed on an "AS IS" BASIS, 15 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 16 | ;; implied. See the License for the specific language governing 17 | ;; permissions and limitations under the License. 18 | 19 | ;;; Commentary: 20 | 21 | ;; This library provides an advanced LSP feature for `lean4-mode'. 22 | 23 | ;;; Code: 24 | 25 | (require 'dash) 26 | (require 'lean4-syntax) 27 | (require 'lean4-settings) 28 | (require 'lsp-mode) 29 | (require 'lsp-protocol) 30 | (require 'magit-section) 31 | 32 | (defgroup lean4-info nil 33 | "Lean4-Mode Info." 34 | :group 'lean4) 35 | 36 | ;; Lean Info Mode (for "*lean4-info*" buffer) 37 | ;; Automode List 38 | ;;;###autoload 39 | (define-derived-mode lean4-info-mode prog-mode "Lean-Info" 40 | "Major mode for Lean4-Mode Info Buffer." 41 | :syntax-table lean4-syntax-table 42 | :group 'lean4 43 | (set (make-local-variable 'font-lock-defaults) lean4-info-font-lock-defaults) 44 | (set (make-local-variable 'indent-tabs-mode) nil) 45 | (set 'compilation-mode-font-lock-keywords '()) 46 | (set (make-local-variable 'lisp-indent-function) 47 | 'common-lisp-indent-function)) 48 | 49 | (defun lean4-ensure-info-buffer (buffer) 50 | "Create BUFFER if it does not exist. 51 | Also choose settings used for the *Lean Goal* buffer." 52 | (unless (get-buffer buffer) 53 | (with-current-buffer (get-buffer-create buffer) 54 | (buffer-disable-undo) 55 | (magit-section-mode) 56 | (set-syntax-table lean4-syntax-table) 57 | (setq buffer-read-only t)))) 58 | 59 | (defun lean4-toggle-info-buffer (buffer) 60 | "Create or delete BUFFER. 61 | The buffer is supposed to be the *Lean Goal* buffer." 62 | (-if-let (window (get-buffer-window buffer)) 63 | (quit-window nil window) 64 | (lean4-ensure-info-buffer buffer) 65 | (display-buffer buffer))) 66 | 67 | (defun lean4-info-buffer-active (buffer) 68 | "Check whether given info BUFFER should show info for current buffer." 69 | (and 70 | ;; info buffer visible (on any frame) 71 | (get-buffer-window buffer t) 72 | ;; current window of current buffer is selected (i.e., in focus) 73 | (eq (current-buffer) (window-buffer)))) 74 | 75 | (eval-and-compile 76 | (lsp-interface 77 | (lean:PlainGoal (:goals) nil) 78 | (lean:PlainTermGoal (:goal) nil) 79 | (lean:Diagnostic 80 | (:range :fullRange :message) 81 | (:code :relatedInformation :severity :source :tags)))) 82 | 83 | (defconst lean4-info-buffer-name "*Lean Goal*") 84 | 85 | (defvar lean4-goals nil) 86 | (defvar lean4-term-goal nil) 87 | 88 | (lsp-defun lean4-diagnostic-full-start-line ((&lean:Diagnostic :full-range (&Range :start (&Position :line)))) 89 | line) 90 | (lsp-defun lean4-diagnostic-full-end-line ((&lean:Diagnostic :full-range (&Range :end (&Position :line)))) 91 | line) 92 | 93 | (defun lean4-info--error-button-action (data) 94 | (let ((buffer (nth 0 data)) 95 | (line (nth 1 data)) 96 | (column (nth 2 data))) 97 | (when (buffer-live-p buffer) 98 | (pop-to-buffer buffer) 99 | (goto-char (point-min)) 100 | (forward-line (1- line)) 101 | (forward-char column)))) 102 | 103 | (defun lean4-info--insert-highlight-inaccessible-names (&rest text) 104 | (let ((begin (point))) 105 | (apply #'insert text) 106 | (when lean4-highlight-inaccessible-names 107 | (let ((end (point-marker))) 108 | (goto-char begin) 109 | (while (re-search-forward "\\(\\sw+\\)✝\\([¹²³⁴-⁹⁰]*\\)" end t) 110 | (replace-match 111 | (propertize (concat (match-string-no-properties 1) 112 | (match-string-no-properties 2)) 113 | 'font-lock-face 'font-lock-comment-face) 114 | 'fixedcase 'literal)) 115 | (goto-char end))))) 116 | 117 | (defun lean4--insert-goal-text (text delimiter) 118 | (lean4-info--insert-highlight-inaccessible-names 119 | (lsp--fontlock-with-mode text 'lean4-info-mode) 120 | delimiter)) 121 | 122 | (defun lean4-info--mk-message-section (value caption messages buffer) 123 | "Add a section with id VALUE, caption CAPTION and contents ERRORS." 124 | (when-let (msgs messages) ;; captured for deferred rendering 125 | (magit-insert-section (magit-section value) 126 | (magit-insert-heading caption) 127 | (magit-insert-section-body 128 | (dolist (e msgs) 129 | (-let (((&Diagnostic :message :range (&Range :start (&Position :line :character))) e)) 130 | (let ((ln (1+ (lsp-translate-line line))) 131 | (col (lsp-translate-column character))) 132 | (insert-text-button (format "%d:%d:" ln col) 133 | 'action #'lean4-info--error-button-action 134 | 'button-data (list buffer ln col) 135 | 'face 'magit-section-heading 136 | 'help-echo "mouse-2: visit this file, line and column")) 137 | (lean4-info--insert-highlight-inaccessible-names "\n" message "\n"))))))) 138 | 139 | (defun lean4-info-buffer-redisplay () 140 | (when (lean4-info-buffer-active lean4-info-buffer-name) 141 | (-let* ((deactivate-mark) ; keep transient mark 142 | (inhibit-read-only t) 143 | (buffer (current-buffer)) 144 | (line (lsp--cur-line)) 145 | (errors (lsp--get-buffer-diagnostics)) 146 | (errors (-sort (-on #'< #'lean4-diagnostic-full-end-line) errors)) 147 | ((errors-above errors) 148 | (--split-with (< (lean4-diagnostic-full-end-line it) line) errors)) 149 | ((errors-here errors-below) 150 | (--split-with (<= (lean4-diagnostic-full-start-line it) line) errors))) 151 | (with-current-buffer lean4-info-buffer-name 152 | (progn 153 | (erase-buffer) 154 | (magit-insert-section (magit-section 'root) 155 | (when-let ((goals lean4-goals)) ;; capture for deferred rendering 156 | (magit-insert-section (magit-section 'goals) 157 | (magit-insert-heading "Goals:") 158 | (magit-insert-section-body 159 | (if (> (length goals) 0) 160 | (seq-doseq (g goals) 161 | (magit-insert-section (magit-section) 162 | (lean4--insert-goal-text g "\n\n"))) 163 | (insert "goals accomplished\n\n"))))) 164 | (when-let ((term-goal lean4-term-goal)) ;; capture for deferred rendering 165 | (magit-insert-section (magit-section 'term-goal) 166 | (magit-insert-heading "Expected type:") 167 | (magit-insert-section-body 168 | (lean4--insert-goal-text term-goal "\n")))) 169 | (lean4-info--mk-message-section 'errors-here "Messages here:" errors-here buffer) 170 | (lean4-info--mk-message-section 'errors-below "Messages below:" errors-below buffer) 171 | (lean4-info--mk-message-section 'errors-above "Messages above:" errors-above buffer))))))) 172 | 173 | ;; Debouncing 174 | ;; ~~~~~~~~~~~ 175 | ;; We want to update the Lean4 info buffer as seldom as possible, 176 | ;; since magit-section is slow at rendering. We 177 | ;; wait a small duration (`debounce-delay-sec') when we get a 178 | ;; redisplay request, to see if there is a redisplay request in the 179 | ;; future that invalidates the current request (debouncing). 180 | ;; Pictorially, 181 | ;; (a) One request: 182 | ;; --r1 183 | ;; --r1.wait 184 | ;; ----------r1.render 185 | ;; (b) Two requests in quick succession: 186 | ;; --r1 187 | ;; --r1.wait 188 | ;; --------r2(cancel r1.wait) 189 | ;; --------r2.wait 190 | ;; ---------------r2.render 191 | ;; (c) Two requests, not in succession: 192 | ;; --r1 193 | ;; --r1.wait 194 | ;; ---------r1.render 195 | ;; ------------------r2 196 | ;; ------------------r2.wait 197 | ;; -------------------------r2.render 198 | ;; This delaying can lead to a pathological case where we continually 199 | ;; stagger, while not rendering anything: 200 | ;; --r1 201 | ;; --r1.wait 202 | ;; --------r2(cancel r1.wait) 203 | ;; --------r2.wait 204 | ;; --------------r3(cancel r2.wait) 205 | ;; ---------------r3.wait 206 | ;; ---------------------r4(cancel r3.wait) 207 | ;; ---------------------... 208 | ;; We prevent this pathological case by keeping track of when 209 | ;; when we began debouncing in `lean4-info-buffer-debounce-begin-time'. 210 | ;; If we have been debouncing for longer than 211 | ;; `lean4-info-buffer-debounce-upper-bound-sec', then we 212 | ;; immediately write instead of debouncing; 213 | ;; `max-debounces' times. Upon trying to stagger the 214 | ;; `max-debounces'th request, we immediately render: 215 | ;; begin-time:nil----t0----------------nil------- 216 | ;; -------r1 | 217 | ;; -------r1.wait | 218 | ;; -------|-----r2(cancel r1.wait) 219 | ;; -------|-----r2.wait | 220 | ;; -------|-----------r3(cancel r2.wait) 221 | ;; -------|-----------r3.wait 222 | ;; -------|-----------------r4(cancel r3.wait) 223 | ;; -------|-----------------| 224 | ;; >-----------------< 225 | ;; >longer than `debounce-upper-bound-sec'< 226 | ;; -------------------------r4.render(FORCED) 227 | 228 | 229 | (defcustom lean4-info-buffer-debounce-delay-sec 0.1 230 | "Duration of time we wait before writing to *Lean Goal*." 231 | :group 'lean4-info 232 | :type 'number) 233 | 234 | 235 | (defvar lean4-info-buffer-debounce-timer nil 236 | "Timer that is used to debounce Lean4 info view refresh.") 237 | 238 | 239 | (defvar lean4-info-buffer-debounce-begin-time nil 240 | "Return the time we have begun debouncing. 241 | 242 | The returned value is nil if we are not currently debouncing. 243 | Otherwise, is a timestamp as given by `current-time'.") 244 | 245 | (defcustom lean4-info-buffer-debounce-upper-bound-sec 246 | 0.5 247 | "Maximum time we are allowed to stagger debouncing. 248 | 249 | If we recieve a request such that we have been debouncing for longer 250 | than `lean4-info-buffer-debounce-begin-time', then we immediately run 251 | the request." 252 | :group 'lean4-info 253 | :type 'number) 254 | 255 | ;; Debounce implementation modifed from lsp-lens 256 | ;; https://github.com/emacs-lsp/lsp-mode/blob/2f0ea2e396ec9a570f2a2aeb097c304ddc61ebee/lsp-lens.el#L140 257 | (defun lean4-info-buffer-redisplay-debounced () 258 | "Debounced version of `lean4-info-buffer-redisplay'. 259 | 260 | This version ensures that info buffer is not repeatedly written to. 261 | This is to prevent lag, because magit is quite slow at building 262 | sections." 263 | ;; if we have not begun debouncing, setup debouncing begin time. 264 | (if (not lean4-info-buffer-debounce-begin-time) 265 | (setq lean4-info-buffer-debounce-begin-time (current-time))) 266 | ;; if time since we began debouncing is too long... 267 | (if (>= (time-to-seconds 268 | (time-subtract (current-time) 269 | lean4-info-buffer-debounce-begin-time)) 270 | lean4-info-buffer-debounce-upper-bound-sec) 271 | ;; then redisplay immediately. 272 | (progn 273 | ;; We have stopped debouncing. 274 | (setq lean4-info-buffer-debounce-begin-time nil) 275 | (lean4-info-buffer-redisplay)) 276 | ;; else cancel current timer, create new debounced timer. 277 | (-some-> lean4-info-buffer-debounce-timer cancel-timer) 278 | (setq lean4-info-buffer-debounce-timer ; set new timer 279 | (run-with-timer 280 | lean4-info-buffer-debounce-delay-sec 281 | nil ; don't repeat timer 282 | (lambda () 283 | ;; We have stopped debouncing. 284 | (setq lean4-info-buffer-debounce-begin-time nil) 285 | (lean4-info-buffer-redisplay)))))) 286 | 287 | 288 | (defun lean4-info-buffer-refresh () 289 | "Refresh the *Lean Goal* buffer." 290 | (when (lean4-info-buffer-active lean4-info-buffer-name) 291 | (lsp-request-async 292 | "$/lean/plainGoal" 293 | (lsp--text-document-position-params) 294 | (-lambda ((ignored &as &lean:PlainGoal? :goals)) 295 | (setq lean4-goals goals) 296 | (lean4-info-buffer-redisplay-debounced)) 297 | :error-handler #'ignore 298 | :mode 'tick 299 | :cancel-token :plain-goal) 300 | (lsp-request-async 301 | "$/lean/plainTermGoal" 302 | (lsp--text-document-position-params) 303 | (-lambda ((ignored &as &lean:PlainTermGoal? :goal)) 304 | (setq lean4-term-goal goal) 305 | (lean4-info-buffer-redisplay-debounced)) 306 | :error-handler #'ignore 307 | :mode 'tick 308 | :cancel-token :plain-term-goal) 309 | ;; may lead to flickering 310 | ;(lean4-info-buffer-redisplay) 311 | )) 312 | 313 | (defun lean4-toggle-info () 314 | "Show infos at the current point." 315 | (interactive) 316 | (lean4-toggle-info-buffer lean4-info-buffer-name) 317 | (lean4-info-buffer-refresh)) 318 | 319 | (provide 'lean4-info) 320 | ;;; lean4-info.el ends here 321 | -------------------------------------------------------------------------------- /lean4-input.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-input.el --- Lean4-Mode Input Method -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2005-2012 Ulf Norell, Nils Anders Danielsson, 4 | ;; Catarina Coquand, Makoto Takeyama, Andreas Abel, Karl Mehltretter, 5 | ;; Marcin Benke, Darin Morrison. 6 | 7 | ;; This file is not part of GNU Emacs. 8 | 9 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 10 | ;; may not use this file except in compliance with the License. You 11 | ;; may obtain a copy of the License at 12 | ;; 13 | ;; http://www.apache.org/licenses/LICENSE-2.0 14 | ;; 15 | ;; Unless required by applicable law or agreed to in writing, software 16 | ;; distributed under the License is distributed on an "AS IS" BASIS, 17 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 18 | ;; implied. See the License for the specific language governing 19 | ;; permissions and limitations under the License. 20 | 21 | ;;; Commentary: 22 | 23 | ;; A highly customisable input method which can inherit from other 24 | ;; Quail input methods. By default the input method is geared towards 25 | ;; the input of mathematical and other symbols in Lean programs. 26 | 27 | ;; Use M-x customize-group lean4-input to customise this input method. 28 | ;; Note that the functions defined under "Functions used to tweak 29 | ;; translation pairs" below can be used to tweak both the key 30 | ;; translations inherited from other input methods as well as the 31 | ;; ones added specifically for this one. 32 | 33 | ;; Use lean4-input-show-translations to see all the characters which 34 | ;; can be typed using this input method (except for those 35 | ;; corresponding to ASCII characters). 36 | 37 | ;; This file is based on agda-input.el from Agda-Mode: 38 | ;; https://github.com/agda/agda/blob/d2cbd2dd4f49fa84c5ca6fcf464c3211adcc0088/src/data/emacs-mode/agda-input.el 39 | 40 | ;;; Code: 41 | 42 | (require 'quail) 43 | (require 'cl-lib) 44 | (require 'subr-x) 45 | (require 'dash) 46 | (require 'map) 47 | 48 | ;; Quail is quite stateful, so be careful when editing this code. Note 49 | ;; that with-temp-buffer is used below whenever buffer-local state is 50 | ;; modified. 51 | 52 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 53 | ;; Utility functions 54 | 55 | (defun lean4-input-concat-map (f xs) 56 | "Concat (map F XS)." 57 | (apply #'append (mapcar f xs))) 58 | 59 | (defun lean4-input-to-string-list (s) 60 | "Convert a string S to a list of one-character strings. 61 | First remove all space and newline characters." 62 | (lean4-input-concat-map 63 | (lambda (c) (if (member c (string-to-list " \n")) 64 | nil 65 | (list (string c)))) 66 | (string-to-list s))) 67 | 68 | (defun lean4-input-character-range (from to) 69 | "A string consisting of the characters from FROM to TO." 70 | (let (seq) 71 | (dotimes (i (1+ (- to from))) 72 | (setq seq (cons (+ from i) seq))) 73 | (concat (nreverse seq)))) 74 | 75 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 76 | ;; Functions used to tweak translation pairs 77 | 78 | (defun lean4-input-compose (f g) 79 | "\\x -> concatMap F (G x)." 80 | (lambda (x) (lean4-input-concat-map f (funcall g x)))) 81 | 82 | (defun lean4-input-or (f g) 83 | "\\x -> F x ++ G x." 84 | (lambda (x) (append (funcall f x) (funcall g x)))) 85 | 86 | (defun lean4-input-nonempty () 87 | "Only keep pairs with a non-empty first component." 88 | (lambda (x) (if (> (length (car x)) 0) (list x)))) 89 | 90 | (defun lean4-input-prepend (prefix) 91 | "Prepend PREFIX to all key sequences." 92 | (lambda (x) `((,(concat prefix (car x)) . ,(cdr x))))) 93 | 94 | (defun lean4-input-prefix (prefix) 95 | "Only keep pairs whose key sequence starts with PREFIX." 96 | (lambda (x) 97 | (if (equal (substring (car x) 0 (length prefix)) prefix) 98 | (list x)))) 99 | 100 | (defun lean4-input-suffix (suffix) 101 | "Only keep pairs whose key sequence ends with SUFFIX." 102 | (lambda (x) 103 | (if (equal (substring (car x) 104 | (- (length (car x)) (length suffix))) 105 | suffix) 106 | (list x)))) 107 | 108 | (defun lean4-input-drop (ss) 109 | "Drop pairs matching one of the given key sequences. 110 | SS should be a list of strings." 111 | (lambda (x) (unless (member (car x) ss) (list x)))) 112 | 113 | (defun lean4-input-drop-beginning (n) 114 | "Drop N characters from the beginning of each key sequence." 115 | (lambda (x) `((,(substring (car x) n) . ,(cdr x))))) 116 | 117 | (defun lean4-input-drop-end (n) 118 | "Drop N characters from the end of each key sequence." 119 | (lambda (x) 120 | `((,(substring (car x) 0 (- (length (car x)) n)) . 121 | ,(cdr x))))) 122 | 123 | (defun lean4-input-drop-prefix (prefix) 124 | "Only keep pairs whose key sequence starts with PREFIX. 125 | This prefix is dropped." 126 | (lean4-input-compose 127 | (lean4-input-drop-beginning (length prefix)) 128 | (lean4-input-prefix prefix))) 129 | 130 | (defun lean4-input-drop-suffix (suffix) 131 | "Only keep pairs whose key sequence ends with SUFFIX. 132 | This suffix is dropped." 133 | (lean4-input-compose 134 | (lean4-input-drop-end (length suffix)) 135 | (lean4-input-suffix suffix))) 136 | 137 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 138 | ;; Customization 139 | 140 | ;; The :set keyword is set to 'lean4-input-incorporate-changed-setting 141 | ;; so that the input method gets updated immediately when users 142 | ;; customize it. However, the setup functions cannot be run before all 143 | ;; variables have been defined. Hence the :initialize keyword is set to 144 | ;; 'custom-initialize-default to ensure that the setup is not performed 145 | ;; until lean4-input-setup is called at the end of this file. 146 | 147 | (defgroup lean4-input nil 148 | "The Lean input method. 149 | After tweaking these settings you may want to inspect the resulting 150 | translations using `lean4-input-show-translations'." 151 | :group 'lean4 152 | :group 'leim) 153 | 154 | (defcustom lean4-input-inherit 155 | `(("TeX" . (lean4-input-compose 156 | (lean4-input-drop '("geq" "leq" "bullet" "qed" "par")) 157 | (lean4-input-or 158 | (lean4-input-drop-prefix "\\") 159 | (lean4-input-or 160 | (lean4-input-compose 161 | (lean4-input-drop '("^o")) 162 | (lean4-input-prefix "^")) 163 | (lean4-input-prefix "_")))))) 164 | "List of parent Quail input methods. 165 | Translations from these methods will be inherited by the Lean 166 | input method (with the exception of translations corresponding to 167 | ASCII characters). 168 | 169 | The list consists of pairs (qp . tweak), where qp is the name of 170 | a Quail package, and tweak is an expression of the same signature as 171 | the argument of `lean4-input-add-translations'. 172 | 173 | The inherited translation pairs are added last, after 174 | `lean4-input-user-translations' and `lean4-input-translations'. 175 | 176 | If you change this setting manually (without using the 177 | customization buffer) you need to call `lean4-input-setup' in 178 | order for the change to take effect." 179 | :group 'lean4-input 180 | :set 'lean4-input-incorporate-changed-setting 181 | :initialize 'custom-initialize-default 182 | :type '(repeat (cons (string :tag "Quail package") 183 | (sexp :tag "Tweaking function")))) 184 | 185 | (defcustom lean4-input-data-directory 186 | (expand-file-name "data/" (file-name-directory (or load-file-name (buffer-file-name)))) 187 | "Directory in which abbreviations.json resides." 188 | :group 'lean4-input 189 | :type 'directory) 190 | 191 | (defcustom lean4-input-user-translations nil 192 | "A list of translations specific to the Lean input method. 193 | Each element is a pair (KEY-SEQUENCE-STRING . LIST-OF-TRANSLATION-STRINGS). 194 | All the translation strings are possible translations 195 | of the given key sequence; if there is more than one you can choose 196 | between them using the arrow keys. 197 | 198 | These translation pairs are included first, before thoseinherited 199 | from other input methods." 200 | :group 'lean4-input 201 | :set 'lean4-input-incorporate-changed-setting 202 | :initialize 'custom-initialize-default 203 | :type '(repeat (cons (string :tag "Key sequence") 204 | (repeat :tag "Translations" string)))) 205 | 206 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 207 | ;; Inspecting and modifying translation maps 208 | 209 | (defun lean4-input-get-translations (qp) 210 | "Return all translations from the Quail package QP. 211 | Result is a list of pairs (KEY-SEQUENCE . TRANSLATION) 212 | that contains all translations from QP Except for those corresponding to ASCII." 213 | (with-temp-buffer 214 | (activate-input-method qp) ; To make sure that the package is loaded. 215 | (unless (quail-package qp) 216 | (error "%s is not a Quail package" qp)) 217 | (let ((decode-map (list 'decode-map))) 218 | (quail-build-decode-map (list (quail-map)) "" decode-map 0) 219 | (cdr decode-map)))) 220 | 221 | (defun lean4-input-show-translations (qp) 222 | "Display all translations used by the Quail package QP (a string). 223 | \(Except for those corresponding to ASCII)." 224 | (interactive (list (read-input-method-name 225 | "Quail input method (default %s): " "Lean"))) 226 | (let ((buf (concat "*" qp " input method translations*"))) 227 | (with-output-to-temp-buffer buf 228 | (with-current-buffer buf 229 | (quail-insert-decode-map 230 | (cons 'decode-map (lean4-input-get-translations qp))))))) 231 | 232 | (defun lean4-input-add-translations (trans) 233 | "Add the given translations TRANS to the Lean input method. 234 | TRANS is a list of pairs (KEY-SEQUENCE . TRANSLATION). The 235 | translations are appended to the current translations." 236 | (with-temp-buffer 237 | (map-do (lambda (key tr) 238 | (when key 239 | (quail-defrule (concat "\\" key) 240 | tr 241 | "Lean" t))) 242 | trans))) 243 | 244 | (defun lean4-input-inherit-package (qp &optional fun) 245 | "Inherit translations from the Quail package QP. 246 | Add all translations from the Quail package QP (except for those 247 | corresponding to ASCII) to the list of Lean Quail rules. 248 | 249 | The optional function FUN can be used to modify the translations. 250 | It is given a pair (KEY-SEQUENCE . TRANSLATION) and should return 251 | a list of such pairs." 252 | (let ((trans (lean4-input-get-translations qp))) 253 | (lean4-input-add-translations 254 | (if fun (lean4-input-concat-map fun trans) 255 | trans)))) 256 | 257 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 258 | ;; Setting up the input method 259 | 260 | (defvar json-key-type) 261 | (declare-function json-read "json") 262 | 263 | (defun lean4-input-setup () 264 | "Set up the Lean input method. 265 | Use customisable variables and parent input methods to setup Lean input method." 266 | 267 | ;; Create (or reset) the input method. 268 | (with-temp-buffer 269 | (quail-define-package "Lean" "UTF-8" "∏" t ; guidance 270 | "Lean input method. 271 | The purpose of this input method is to edit Lean programs, but 272 | since it is highly customisable it can be made useful for other 273 | tasks as well." 274 | nil nil nil nil nil nil t ; maximum-shortest 275 | )) 276 | 277 | (lean4-input-add-translations (mapcar (lambda (tr) (cons (car tr) (vconcat (cdr tr)))) 278 | lean4-input-user-translations)) 279 | (with-temp-buffer 280 | (insert-file-contents (expand-file-name 281 | "abbreviations.json" 282 | lean4-input-data-directory)) 283 | (thread-last 284 | (let ((json-key-type 'string)) ;; make sure json key is a string. 285 | ;; Prefer emacs native support implemented in C (since 27.1). 286 | ;; Back-up is still useful in case Emacs in not compiled `--with-json`. 287 | (if (fboundp 'json-parse-buffer) 288 | (json-parse-buffer) 289 | (require 'json) 290 | (json-read))) 291 | (map-filter (lambda (_ s) (not (string-match-p "\\$CURSOR" s)))) 292 | (map-apply (lambda (k s) (cons k (vector s)))) 293 | lean4-input-add-translations)) 294 | (dolist (def lean4-input-inherit) 295 | (lean4-input-inherit-package (car def) 296 | (eval (cdr def))))) 297 | 298 | (defun lean4-input-incorporate-changed-setting (sym val) 299 | "Update the Lean input method. 300 | Set SYM default value to VAL, then call `lean4-input-setup'. 301 | Suitable for use in the :set field of `defcustom'." 302 | (set-default sym val) 303 | (lean4-input-setup)) 304 | 305 | ;; Set up the input method. 306 | 307 | (cl-eval-when (load eval) 308 | (lean4-input-setup)) 309 | 310 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 311 | ;; Export Translations 312 | 313 | (defun lean4-input-export-translations () 314 | "Export the current translations in a javascript format. 315 | Print (input, output) pairs in Javascript format to the buffer 316 | *lean4-translations*. The output can be copy-pasted to 317 | leanprover.github.io/tutorial/js/input-method.js" 318 | (interactive) 319 | (with-current-buffer 320 | (get-buffer-create "*lean4-translations*") 321 | (let ((exclude-list '("\\newline"))) 322 | (insert "var corrections = {") 323 | (--each 324 | (--filter (not (member (car it) exclude-list)) 325 | (lean4-input-get-translations "Lean")) 326 | (let* ((input (substring (car it) 1)) 327 | (outputs (cdr it))) 328 | (insert (format "%s:\"" (prin1-to-string input))) 329 | (cond ((vectorp outputs) 330 | (insert (elt outputs 0))) 331 | (t (insert-char outputs))) 332 | (insert (format "\",\n")))) 333 | (insert "};")))) 334 | 335 | (defun lean4-input-export-translations-to-stdout () 336 | "Print current translations to stdout." 337 | (lean4-input-export-translations) 338 | (with-current-buffer "*lean4-translations*" 339 | (princ (buffer-string)))) 340 | 341 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 342 | ;; Administrative details 343 | 344 | (provide 'lean4-input) 345 | ;;; lean4-input.el ends here 346 | -------------------------------------------------------------------------------- /lean4-lake.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-lake.el --- Lean4-Mode Lake Integration -*- lexical-binding: t; -*- 2 | 3 | ;; This file is not part of GNU Emacs. 4 | 5 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 6 | ;; may not use this file except in compliance with the License. You 7 | ;; may obtain a copy of the License at 8 | ;; 9 | ;; http://www.apache.org/licenses/LICENSE-2.0 10 | ;; 11 | ;; Unless required by applicable law or agreed to in writing, software 12 | ;; distributed under the License is distributed on an "AS IS" BASIS, 13 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | ;; implied. See the License for the specific language governing 15 | ;; permissions and limitations under the License. 16 | 17 | ;;; Commentary: 18 | 19 | ;; This library provides integration with Lake, Lean 4 build system and package 20 | ;; manager. 21 | 22 | ;;; Code: 23 | 24 | (require 'lean4-util) 25 | (require 'lean4-settings) 26 | 27 | (defun lean4-root-dir-p (dir) 28 | "Check if directory DIR contains \"lakefile.lean\" or \"lakefile.toml\"." 29 | (or 30 | (file-exists-p (expand-file-name "lakefile.lean" dir)) 31 | (file-exists-p (expand-file-name "lakefile.toml" dir)))) 32 | 33 | (defun lean4-lake-find-dir () 34 | "Find a parent directory of the current file with a Lake file. 35 | 36 | It looks for files named \"lakefile.lean\" or \"lakefile.toml\" file." 37 | (and (buffer-file-name) 38 | (locate-dominating-file (buffer-file-name) #'lean4-root-dir-p))) 39 | 40 | (defun lean4-lake-find-dir-safe () 41 | "Call `lean4-lake-find-dir', error on failure." 42 | (or (lean4-lake-find-dir) 43 | (error "Cannot find lakefile in any directory above %s" (buffer-file-name)))) 44 | 45 | (defun lean4-lake-build () 46 | "Call lake build." 47 | (interactive) 48 | (let ((default-directory (file-name-as-directory (lean4-lake-find-dir-safe)))) 49 | (compile (concat (lean4-get-executable lean4-lake-name) " build")))) 50 | 51 | (provide 'lean4-lake) 52 | ;;; lean4-lake.el ends here 53 | -------------------------------------------------------------------------------- /lean4-mode.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-mode.el --- Major mode for Lean language -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2013, 2014 Microsoft Corporation. All rights reserved. 4 | ;; Copyright (c) 2014, 2015 Soonho Kong. All rights reserved. 5 | 6 | ;; Author: Leonardo de Moura 7 | ;; Soonho Kong 8 | ;; Gabriel Ebner 9 | ;; Sebastian Ullrich 10 | ;; Maintainer: Yury G. Kudryashov 11 | ;; Created: Jan 09, 2014 12 | ;; Keywords: languages 13 | ;; Package-Requires: ((emacs "27.1") (compat "28.1") (dash "2.18.0") (magit-section "2.90.1") (lsp-mode "8.0.0")) 14 | ;; URL: https://github.com/leanprover-community/lean4-mode 15 | ;; SPDX-License-Identifier: Apache-2.0 16 | ;; Version: 1.1.2 17 | 18 | ;; This file is not part of GNU Emacs. 19 | 20 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 21 | ;; may not use this file except in compliance with the License. You 22 | ;; may obtain a copy of the License at 23 | ;; 24 | ;; http://www.apache.org/licenses/LICENSE-2.0 25 | ;; 26 | ;; Unless required by applicable law or agreed to in writing, software 27 | ;; distributed under the License is distributed on an "AS IS" BASIS, 28 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 29 | ;; implied. See the License for the specific language governing 30 | ;; permissions and limitations under the License. 31 | 32 | ;;; Commentary: 33 | 34 | ;; Provides a major mode for the Lean programming language. 35 | 36 | ;; Provides highlighting, diagnostics, goal visualization, 37 | ;; and many other useful features for Lean users. 38 | 39 | ;; See the README.md for more advanced features and the 40 | ;; associated keybindings. 41 | 42 | ;;; Code: 43 | 44 | (require 'cl-lib) 45 | (require 'dash) 46 | (require 'pcase) 47 | (require 'lsp-mode) 48 | (require 'lean4-eri) 49 | (require 'lean4-util) 50 | (require 'lean4-settings) 51 | (require 'lean4-syntax) 52 | (require 'lean4-info) 53 | (require 'lean4-fringe) 54 | (require 'lean4-lake) 55 | 56 | ;; Declare symbols defined in external dependencies. This silences 57 | ;; byte-compiler warnings: 58 | (defvar compilation-mode-font-lock-keywords) 59 | (defvar flycheck-after-syntax-check-hook) 60 | (defvar flycheck-disabled-checkers) 61 | (defvar flycheck-mode) 62 | (defvar lsp--cur-version) 63 | (defvar markdown-code-lang-modes) 64 | (declare-function flycheck-list-errors "ext:flycheck") 65 | (declare-function flymake-proc-init-create-temp-buffer-copy "flymake-proc") 66 | (declare-function lean-mode "ext:lean-mode") 67 | (declare-function quail-show-key "quail") 68 | 69 | (defun lean4-compile-string (lake-name exe-name args file-name) 70 | "Command to run EXE-NAME with extra ARGS and FILE-NAME. 71 | If LAKE-NAME is nonempty, then prepend \"LAKE-NAME env\" to the command 72 | \"EXE-NAME ARGS FILE-NAME\"." 73 | (if lake-name 74 | (format "%s env %s %s %s" lake-name exe-name args file-name) 75 | (format "%s %s %s" exe-name args file-name))) 76 | 77 | (defun lean4-create-temp-in-system-tempdir (file-name prefix) 78 | "Create a temp lean file and return its name. 79 | The new file has prefix PREFIX (defaults to `flymake') and the same extension as 80 | FILE-NAME." 81 | (make-temp-file (or prefix "flymake") nil (file-name-extension file-name))) 82 | 83 | (defun lean4-execute (&optional arg) 84 | "Execute Lean in the current buffer with an optional argument ARG." 85 | (interactive) 86 | (when (called-interactively-p 'any) 87 | (setq arg (read-string "arg: " arg))) 88 | (let* ((cc compile-command) 89 | (dd default-directory) 90 | (use-lake (lean4-lake-find-dir)) 91 | (default-directory (if use-lake (lean4-lake-find-dir) dd)) 92 | (target-file-name 93 | (or 94 | (buffer-file-name) 95 | (flymake-proc-init-create-temp-buffer-copy 'lean4-create-temp-in-system-tempdir)))) 96 | (compile (lean4-compile-string 97 | (if use-lake (shell-quote-argument (expand-file-name (lean4-get-executable lean4-lake-name))) nil) 98 | (shell-quote-argument (expand-file-name (lean4-get-executable lean4-executable-name))) 99 | (or arg "") 100 | (shell-quote-argument (expand-file-name target-file-name)))) 101 | ;; restore old value 102 | (setq compile-command cc) 103 | (setq default-directory dd))) 104 | 105 | (defun lean4-std-exe () 106 | "Execute Lean in the current buffer." 107 | (interactive) 108 | (lean4-execute)) 109 | 110 | (defun lean4-refresh-file-dependencies () 111 | "Refresh the file dependencies. 112 | 113 | This function restarts the server subprocess for the current 114 | file, recompiling, and reloading all imports." 115 | (interactive) 116 | (lsp-notify 117 | "textDocument/didClose" 118 | `(:textDocument ,(lsp--text-document-identifier))) 119 | (lsp-notify 120 | "textDocument/didOpen" 121 | (list :textDocument 122 | (list :uri (lsp--buffer-uri) 123 | :languageId (lsp-buffer-language) 124 | :version lsp--cur-version 125 | :text (lsp--buffer-content))))) 126 | 127 | (defun lean4-tab-indent () 128 | "Lean 4 function for TAB indent." 129 | (interactive) 130 | (cond ((looking-back (rx line-start (* white)) nil) 131 | (lean4-eri-indent)) 132 | (t (indent-for-tab-command)))) 133 | 134 | (defun lean4-set-keys () 135 | "Setup Lean 4 keybindings." 136 | (local-set-key lean4-keybinding-std-exe1 #'lean4-std-exe) 137 | (local-set-key lean4-keybinding-std-exe2 #'lean4-std-exe) 138 | (local-set-key lean4-keybinding-show-key #'quail-show-key) 139 | (local-set-key lean4-keybinding-tab-indent #'lean4-tab-indent) 140 | ;; (local-set-key lean4-keybinding-hole #'lean4-hole) 141 | (local-set-key lean4-keybinding-lean4-toggle-info #'lean4-toggle-info) 142 | ;; (local-set-key lean4-keybinding-lean4-message-boxes-toggle #'lean4-message-boxes-toggle) 143 | (local-set-key lean4-keybinding-lake-build #'lean4-lake-build) 144 | (local-set-key lean4-keybinding-refresh-file-dependencies #'lean4-refresh-file-dependencies) 145 | ;; This only works as a mouse binding due to the event, so it is not abstracted 146 | ;; to avoid user confusion. 147 | ;; (local-set-key (kbd "") #'lean4-right-click-show-menu) 148 | ) 149 | 150 | (define-abbrev-table 'lean4-abbrev-table 151 | '()) 152 | 153 | (defvar lean4-mode-map (make-sparse-keymap) 154 | "Keymap used in Lean mode.") 155 | 156 | (easy-menu-define lean4-mode-menu lean4-mode-map 157 | "Menu for the Lean major mode." 158 | `("Lean 4" 159 | ["Execute lean" lean4-execute t] 160 | ["Toggle info display" lean4-toggle-info t] 161 | ;; TODO: Bug#91: We offers a Flycheck-based menu-item when 162 | ;; Flycheck is in use. Users who use built-in Flymake should also 163 | ;; be offered a working menu-item. Alternatively, the menu-item 164 | ;; could also be dropped for both cases. 165 | ["List of errors" flycheck-list-errors flycheck-mode] 166 | ["Restart lean process" lsp-workspace-restart t] 167 | ["Customize lean4-mode" (customize-group 'lean) t])) 168 | 169 | (defconst lean4-hooks-alist 170 | '( 171 | ;; Handle events that may start automatic syntax checks 172 | (before-save-hook . lean4-whitespace-cleanup) 173 | ;; info view 174 | ;; update errors immediately, but delay querying goal 175 | (flycheck-after-syntax-check-hook . lean4-info-buffer-redisplay-debounced) 176 | (post-command-hook . lean4-info-buffer-redisplay-debounced) 177 | (lsp-on-idle-hook . lean4-info-buffer-refresh)) 178 | "Hooks which lean4-mode needs to hook in. 179 | 180 | The `car' of each pair is a hook variable, the `cdr' a function 181 | to be added or removed from the hook variable if Flycheck mode is 182 | enabled and disabled respectively.") 183 | 184 | (defun lean4-mode-setup () 185 | "Default lean4-mode setup." 186 | ;; Right click menu sources 187 | ;;(setq lean4-right-click-item-functions '(lean4-info-right-click-find-definition 188 | ;; lean4-hole-right-click)) 189 | ;; Flycheck 190 | (setq-local flycheck-disabled-checkers '()) 191 | ;; Lean massively benefits from semantic tokens, so change default to enabled 192 | (setq-local lsp-semantic-tokens-enable t) 193 | (lean4-create-lsp-workspace)) 194 | 195 | (defun lean4-create-lsp-workspace () 196 | "Create an LSP workspace. 197 | 198 | Starting from `(buffer-file-name)`, repeatedly look up the 199 | directory hierarchy for a directory containing a file 200 | \"lean-toolchain\", and use the last such directory found, if any. 201 | This allows us to edit files in child packages using the settings 202 | of the parent project." 203 | (let (root) 204 | (when-let ((file-name (buffer-file-name))) 205 | (while-let ((dir (locate-dominating-file file-name "lean-toolchain"))) 206 | ;; We found a toolchain file, but maybe it belongs to a package. 207 | ;; Continue looking until there are no more toolchain files. 208 | (setq root dir 209 | file-name (file-name-directory (directory-file-name dir))))) 210 | (when root 211 | (lsp-workspace-folders-add root)))) 212 | 213 | ;;;###autoload 214 | (define-derived-mode lean4-mode prog-mode "Lean 4" 215 | "Major mode for Lean language. 216 | 217 | \\{lean4-mode-map}" 218 | :syntax-table lean4-syntax-table 219 | :abbrev-table lean4-abbrev-table 220 | :group 'lean4 221 | (set (make-local-variable 'comment-start) "--") 222 | (set (make-local-variable 'comment-start-skip) "[-/]-[ \t]*") 223 | (set (make-local-variable 'comment-end) "") 224 | (set (make-local-variable 'comment-end-skip) "[ \t]*\\(-/\\|\\s>\\)") 225 | (set (make-local-variable 'comment-padding) 1) 226 | (set (make-local-variable 'comment-use-syntax) t) 227 | (set (make-local-variable 'font-lock-defaults) lean4-font-lock-defaults) 228 | (set (make-local-variable 'indent-tabs-mode) nil) 229 | (set 'compilation-mode-font-lock-keywords '()) 230 | (require 'lean4-input) 231 | (set-input-method "Lean") 232 | (set (make-local-variable 'lisp-indent-function) 233 | 'common-lisp-indent-function) 234 | (lean4-set-keys) 235 | (if (fboundp 'electric-indent-local-mode) 236 | (electric-indent-local-mode -1)) 237 | ;; (abbrev-mode 1) 238 | (pcase-dolist (`(,hook . ,fn) lean4-hooks-alist) 239 | (add-hook hook fn nil 'local)) 240 | (lean4-mode-setup)) 241 | 242 | (defun lean4--version () 243 | "Return Lean version as a list `(MAJOR MINOR PATCH)'." 244 | (with-temp-buffer 245 | (call-process (lean4-get-executable "lean") nil (list t nil) nil "-v") 246 | (goto-char (point-min)) 247 | (re-search-forward (rx bol "Lean (version " (group (+ digit) (+ "." (+ digit))))) 248 | (version-to-list (match-string 1)))) 249 | 250 | (defun lean4-show-version () 251 | "Print Lean 4 version." 252 | (interactive) 253 | (message "Lean %s" (mapconcat #'number-to-string (lean4--version) "."))) 254 | 255 | ;;;###autoload 256 | (defun lean4-select-mode () 257 | "Automatically select mode (Lean 3 vs Lean 4)." 258 | (if (and lean4-autodetect-lean3 259 | (eq 3 (car (lean4--version)))) 260 | (lean-mode) 261 | (lean4-mode))) 262 | 263 | ;; Automatically use lean4-mode for .lean files. 264 | ;;;###autoload 265 | (add-to-list 'auto-mode-alist 266 | '("\\.lean\\'" . lean4-select-mode)) 267 | 268 | ;;;###autoload 269 | (with-eval-after-load 'markdown-mode 270 | (add-to-list 'markdown-code-lang-modes 271 | '("lean" . lean4-select-mode))) 272 | 273 | ;; Use utf-8 encoding 274 | ;;;### autoload 275 | (modify-coding-system-alist 'file "\\.lean\\'" 'utf-8) 276 | 277 | ;; LSP init 278 | ;; Ref: https://emacs-lsp.github.io/lsp-mode/page/adding-new-language/ 279 | (add-to-list 'lsp-language-id-configuration 280 | '(lean4-mode . "lean")) 281 | 282 | (defun lean4--server-cmd () 283 | "Return Lean server command. 284 | If found lake version at least 3.1.0, then return '/path/to/lake serve', 285 | otherwise return '/path/to/lean --server'." 286 | (condition-case nil 287 | (if (string-version-lessp (car (process-lines (lean4-get-executable "lake") "--version")) "3.1.0") 288 | `(,(lean4-get-executable lean4-executable-name) "--server") 289 | `(,(lean4-get-executable "lake") "serve")) 290 | (error `(,(lean4-get-executable lean4-executable-name) "--server")))) 291 | 292 | (lsp-register-client 293 | (make-lsp-client :new-connection (lsp-stdio-connection #'lean4--server-cmd) 294 | :major-modes '(lean4-mode) 295 | :server-id 'lean4-lsp 296 | :notification-handlers (ht ("$/lean/fileProgress" #'lean4-fringe-update)) 297 | :semantic-tokens-faces-overrides '(:types (("leanSorryLike" . font-lock-warning-face))))) 298 | 299 | (provide 'lean4-mode) 300 | ;;; lean4-mode.el ends here 301 | -------------------------------------------------------------------------------- /lean4-mode.info: -------------------------------------------------------------------------------- 1 | This is lean4-mode.info, produced by makeinfo version 7.1 from 2 | lean4-mode.texi. 3 | 4 | INFO-DIR-SECTION Emacs misc features 5 | START-INFO-DIR-ENTRY 6 | * Lean4-Mode: (lean4-mode). Emacs major mode for Lean language. 7 | END-INFO-DIR-ENTRY 8 | 9 |  10 | File: lean4-mode.info, Node: Top, Next: Installation, Up: (dir) 11 | 12 | Lean4-Mode - Emacs major mode for Lean language 13 | *********************************************** 14 | 15 | This package extends GNU Emacs (https://www.gnu.org/software/emacs/) by 16 | providing a major mode for editing code written in version 4 of the 17 | programming language and theorem prover Lean (https://lean-lang.org). 18 | 19 | The Lean4-Mode source code is developed at Github 20 | (https://github.com/leanprover-community/lean4-mode) and its issues 21 | tracked there too. Further discussions and question-answering takes 22 | place in the #Emacs channel 23 | (https://leanprover.zulipchat.com/#narrow/channel/468104-Emacs) of 24 | Lean's Zulip chat. 25 | 26 | For legacy version 3 of Lean, use the archived Lean3-Mode 27 | (https://github.com/leanprover/lean3-mode) (also known as _Lean-Mode_). 28 | 29 | * Menu: 30 | 31 | * Installation:: 32 | * Usage:: 33 | * Configuration:: 34 | * Common Pitfalls:: 35 | 36 | -- The Detailed Node Listing -- 37 | 38 | Installation 39 | 40 | * Brief and Generic Instructions:: 41 | * Detailed and Concrete Instructions:: 42 | * Instructions for Source-Based Use-Package:: 43 | 44 | Instructions for Source-Based Use-Package 45 | 46 | * Native vc (Emacs 30 or later):: 47 | * Doom-Emacs:: 48 | * Straight:: 49 | 50 | Usage 51 | 52 | * lsp-mode:: 53 | * Flycheck:: 54 | 55 | Configuration 56 | 57 | * lsp-mode: lsp-mode (1). 58 | * Flycheck: Flycheck (1). 59 | 60 | 61 |  62 | File: lean4-mode.info, Node: Installation, Next: Usage, Prev: Top, Up: Top 63 | 64 | 1 Installation 65 | ************** 66 | 67 | * Menu: 68 | 69 | * Brief and Generic Instructions:: 70 | * Detailed and Concrete Instructions:: 71 | * Instructions for Source-Based Use-Package:: 72 | 73 |  74 | File: lean4-mode.info, Node: Brief and Generic Instructions, Next: Detailed and Concrete Instructions, Up: Installation 75 | 76 | 1.1 Brief and Generic Instructions 77 | ================================== 78 | 79 | First, install the dependencies of Lean4-Mode: 80 | • Lean (https://lean-lang.org/lean4/doc/setup.html) (version 4) 81 | • Emacs (version 27 or later) 82 | • Emacs packages Dash (https://github.com/magnars/dash.el) (available 83 | on GNU-Elpa), lsp-mode (https://emacs-lsp.github.io/lsp-mode), and 84 | Magit-Section 85 | (https://github.com/magit/magit/blob/main/lisp/magit-section.el) 86 | (available on Melpa) 87 | 88 | Second, install Lean4-Mode itself: 89 | • Clone the Git repository of Lean4-Mode 90 | (https://github.com/leanprover-community/lean4-mode). 91 | • In your Emacs initialization file 92 | (https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html), 93 | add the path to that local repository to the ‘load-path’ list. 94 | 95 |  96 | File: lean4-mode.info, Node: Detailed and Concrete Instructions, Next: Instructions for Source-Based Use-Package, Prev: Brief and Generic Instructions, Up: Installation 97 | 98 | 1.2 Detailed and Concrete Instructions 99 | ====================================== 100 | 101 | Install Lean version 4. 102 | 103 | Install Emacs version 27 or later. 104 | 105 | Install the Emacs packages Dash, lsp-mode and Magit-Section. Dash is 106 | the only one of these packages that is available in the default GNU Elpa 107 | (https://elpa.gnu.org) package-archive. You can install the remaining 108 | packages either from source or from Melpa 109 | (https://melpa.org/#/getting-started) package-archive. For later 110 | approach, add the following to your Emacs initialization file (e.g. 111 | ‘~/.emacs.d/init.el’): 112 | 113 | (require 'package) 114 | 115 | (add-to-list 'package-archives 116 | '("melpa" . "https://melpa.org/packages/")) 117 | 118 | (add-to-list 'package-selected-packages 'dash) 119 | (add-to-list 'package-selected-packages 'lsp-mode) 120 | (add-to-list 'package-selected-packages 'magit-section) 121 | 122 | (package-refresh-contents) 123 | (package-install-selected-packages 'no-confirm) 124 | 125 | Clone the Git repository of Lean4-Mode: 126 | 127 | git clone https://github.com/leanprover-community/lean4-mode.git ~/path/to/lean4-mode 128 | 129 | In your Emacs initialization file, add the path to your local 130 | Lean4-Mode repository to the ‘load-path’ list: 131 | (add-to-list 'load-path "~/path/to/lean4-mode") 132 | 133 | Lean4-Mode should now already be enabled when you open a file with 134 | ‘.lean’ extension. But you can optionally also already load Lean4-Mode 135 | on Emacs startup, e.g. in order to customize variables: 136 | (require 'lean4-mode) 137 | 138 |  139 | File: lean4-mode.info, Node: Instructions for Source-Based Use-Package, Prev: Detailed and Concrete Instructions, Up: Installation 140 | 141 | 1.3 Instructions for Source-Based Use-Package 142 | ============================================= 143 | 144 | If you use a source-based package-manager (e.g. ‘package-vc.el’, 145 | Straight or Elpaca), then make sure to list the ‘"data"’ directory in 146 | your Lean4-Mode package recipe. 147 | 148 | If you use the ‘use-package’ macro and intent to defer loading of 149 | packages in order to improve your Emacs startup time, then make sure to 150 | specify ‘lean4-mode’ as a ‘:command’. 151 | 152 | Following subsections show concrete examples. 153 | 154 | * Menu: 155 | 156 | * Native vc (Emacs 30 or later):: 157 | * Doom-Emacs:: 158 | * Straight:: 159 | 160 |  161 | File: lean4-mode.info, Node: Native vc (Emacs 30 or later), Next: Doom-Emacs, Up: Instructions for Source-Based Use-Package 162 | 163 | 1.3.1 Native ‘:vc’ (Emacs 30 or later) 164 | -------------------------------------- 165 | 166 | GNU Emacs comes with ‘use-package.el’ built-in since version 29. And 167 | since version 30, it also comes with a built-in ‘:vc’ keyword for the 168 | ‘use-package’ macro that utilizes ‘package-vc.el’ to install Emacs 169 | packages from remote source repositories. 170 | 171 | (require 'package) 172 | (add-to-list 'package-archives 173 | '("melpa" . "https://melpa.org/packages/")) 174 | (package-initialize) 175 | 176 | (use-package lean4-mode 177 | :commands lean4-mode 178 | :vc (:url "https://github.com/leanprover-community/lean4-mode.git" 179 | :rev :last-release 180 | ;; Or, if you prefer the bleeding edge version of Lean4-Mode: 181 | ;; :rev :newest 182 | )) 183 | 184 |  185 | File: lean4-mode.info, Node: Doom-Emacs, Next: Straight, Prev: Native vc (Emacs 30 or later), Up: Instructions for Source-Based Use-Package 186 | 187 | 1.3.2 Doom-Emacs 188 | ---------------- 189 | 190 | If you use Doom-Emacs, you can place the following code in your Doom 191 | initialization file: 192 | 193 | (package! lean4-mode 194 | :recipe (:host github 195 | :repo "leanprover-community/lean4-mode" 196 | :files ("*.el" "data"))) 197 | 198 |  199 | File: lean4-mode.info, Node: Straight, Prev: Doom-Emacs, Up: Instructions for Source-Based Use-Package 200 | 201 | 1.3.3 Straight 202 | -------------- 203 | 204 | If you use the Straight package manager through Use-Package, then place 205 | the following code in your Emacs initialization file: 206 | 207 | (use-package lean4-mode 208 | :commands lean4-mode 209 | :straight (lean4-mode :type git :host github 210 | :repo "leanprover-community/lean4-mode" 211 | :files ("*.el" "data"))) 212 | 213 |  214 | File: lean4-mode.info, Node: Usage, Next: Configuration, Prev: Installation, Up: Top 215 | 216 | 2 Usage 217 | ******* 218 | 219 | If things are working correctly, you should see the word "Lean 4" in 220 | Emacs mode-line when you open a file with ‘.lean’ extension. Emacs will 221 | ask you to identify the _project_ this file belongs to. If you then 222 | type ‘#check id’, the word ‘#check’ will be underlined, and hovering 223 | over it will show you the type of ‘id’. 224 | 225 | To view the proof state, run ‘lean4-toggle-info’ (‘C-c C-i’). This 226 | will display the ‘*Lean Goals*’ buffer (like the Lean Info-View pane in 227 | VS-Code) in a separate window. 228 | 229 | Key Description Command 230 | ---------------------------------------------------------------------------------------------------------------------- 231 | ‘C-c C-k’ Echo the keystroke needed to input the symbol at point ‘quail-show-key’ 232 | ‘C-c C-d’ Recompile and reload imports ‘lean4-refresh-file-dependencies’ 233 | ‘C-c C-x’ or ‘C-c C-l’ Execute Lean in stand-alone mode ‘lean4-std-exe’ 234 | ‘C-c C-p C-l’ Builds package with lake ‘lean4-lake-build’ 235 | ‘C-c C-i’ Toggle Info-View which shows goals and errors at point ‘lean4-toggle-info-buffer’ 236 | 237 | * Menu: 238 | 239 | * lsp-mode:: 240 | * Flycheck:: 241 | 242 |  243 | File: lean4-mode.info, Node: lsp-mode, Next: Flycheck, Up: Usage 244 | 245 | 2.1 lsp-mode 246 | ============ 247 | 248 | For key bindings from lsp-mode, see its respective documentation 249 | (https://emacs-lsp.github.io/lsp-mode/page/keybindings/) and note that 250 | not all capabilities are supported by Lean4-Mode. 251 | 252 |  253 | File: lean4-mode.info, Node: Flycheck, Prev: lsp-mode, Up: Usage 254 | 255 | 2.2 Flycheck 256 | ============ 257 | 258 | You may optionally use Lean4-Mode together with Flycheck. In that case, 259 | the mode-line will show ‘FlyC:E/N’, indicating that there are ‘E’ number 260 | of errors and ‘N’ number of notes. Following keys will be available by 261 | default (via ‘flycheck-mode-map’): 262 | 263 | Key Description Command 264 | --------------------------------------------------------------- 265 | ‘C-c ! n’ Go to next error ‘flycheck-next-error’ 266 | ‘C-c ! p’ Go to previous error ‘flycheck-previous-error’ 267 | 268 |  269 | File: lean4-mode.info, Node: Configuration, Next: Common Pitfalls, Prev: Usage, Up: Top 270 | 271 | 3 Configuration 272 | *************** 273 | 274 | * Menu: 275 | 276 | * lsp-mode: lsp-mode (1). 277 | * Flycheck: Flycheck (1). 278 | 279 |  280 | File: lean4-mode.info, Node: lsp-mode (1), Next: Flycheck (1), Up: Configuration 281 | 282 | 3.1 lsp-mode 283 | ============ 284 | 285 | If you want breadcrumbs of namespaces and sections to be shown in the 286 | header-line, set the user option ‘lsp-headerline-breadcrumb-enable’ to 287 | ‘t’. 288 | 289 |  290 | File: lean4-mode.info, Node: Flycheck (1), Prev: lsp-mode (1), Up: Configuration 291 | 292 | 3.2 Flycheck 293 | ============ 294 | 295 | Flycheck is an optional but supported dependency of Lean4-Mode. If 296 | Flycheck is installed, lsp-mode and thus Lean4-Mode will by default use 297 | it. If you want to customize this behavior, e.g. if you'd like to use 298 | Emacs' built-in Flymake package instead of Flycheck while keeping later 299 | installed, then customize the ‘lsp-diagnostics-provider’ user option 300 | accordingly. 301 | 302 |  303 | File: lean4-mode.info, Node: Common Pitfalls, Prev: Configuration, Up: Top 304 | 305 | 4 Common Pitfalls 306 | ***************** 307 | 308 | Lean4-Mode only supports version 4 of Lean. For editing Lean version 3, 309 | use Lean3-Mode (https://github.com/leanprover/lean3-mode), which is also 310 | known as Lean-Mode due to historical reasons. In principle, it is fine 311 | to have both Lean3-Mode and Lean4-Mode installed at the same time. But 312 | note that Lean3-Mode uses the prefix ‘lean-’ for its symbols. E.g. you 313 | should not use ‘lean-’-prefixed commands in a buffer with Lean4-Mode as 314 | major mode. 315 | 316 | 317 |  318 | Tag Table: 319 | Node: Top223 320 | Node: Installation1492 321 | Node: Brief and Generic Instructions1735 322 | Node: Detailed and Concrete Instructions2684 323 | Node: Instructions for Source-Based Use-Package4341 324 | Node: Native vc (Emacs 30 or later)5062 325 | Node: Doom-Emacs5970 326 | Node: Straight6396 327 | Node: Usage6896 328 | Node: lsp-mode8342 329 | Node: Flycheck8627 330 | Node: Configuration9237 331 | Node: lsp-mode (1)9427 332 | Node: Flycheck (1)9696 333 | Node: Common Pitfalls10181 334 |  335 | End Tag Table 336 | 337 |  338 | Local Variables: 339 | coding: utf-8 340 | End: 341 | -------------------------------------------------------------------------------- /lean4-mode.texi: -------------------------------------------------------------------------------- 1 | \input texinfo @c -*- texinfo -*- 2 | @c %**start of header 3 | @setfilename lean4-mode.info 4 | @settitle Lean4-Mode - Emacs major mode for Lean language 5 | @documentencoding UTF-8 6 | @documentlanguage en 7 | @c %**end of header 8 | 9 | @dircategory Emacs misc features 10 | @direntry 11 | * Lean4-Mode: (lean4-mode). Emacs major mode for Lean language. 12 | @end direntry 13 | 14 | @finalout 15 | @titlepage 16 | @title Lean4-Mode - Emacs major mode for Lean language 17 | @end titlepage 18 | 19 | @contents 20 | 21 | @ifnottex 22 | @node Top 23 | @top Lean4-Mode - Emacs major mode for Lean language 24 | 25 | This package extends @uref{https://www.gnu.org/software/emacs/, GNU Emacs} by providing a major mode for editing 26 | code written in version 4 of the programming language and theorem 27 | prover @uref{https://lean-lang.org, Lean}. 28 | 29 | The Lean4-Mode source code is developed at @uref{https://github.com/leanprover-community/lean4-mode, Github} and its issues 30 | tracked there too. Further discussions and question-answering takes 31 | place in the @uref{https://leanprover.zulipchat.com/#narrow/channel/468104-Emacs, #Emacs channel} of Lean's Zulip chat. 32 | 33 | For legacy version 3 of Lean, use the archived @uref{https://github.com/leanprover/lean3-mode, Lean3-Mode} (also known 34 | as @emph{Lean-Mode}). 35 | 36 | @end ifnottex 37 | 38 | @menu 39 | * Installation:: 40 | * Usage:: 41 | * Configuration:: 42 | * Common Pitfalls:: 43 | 44 | @detailmenu 45 | --- The Detailed Node Listing --- 46 | 47 | Installation 48 | 49 | * Brief and Generic Instructions:: 50 | * Detailed and Concrete Instructions:: 51 | * Instructions for Source-Based Use-Package:: 52 | 53 | Instructions for Source-Based Use-Package 54 | 55 | * Native @samp{vc} (Emacs 30 or later):: 56 | * Doom-Emacs:: 57 | * Straight:: 58 | 59 | Usage 60 | 61 | * lsp-mode:: 62 | * Flycheck:: 63 | 64 | Configuration 65 | 66 | * lsp-mode: lsp-mode (1). 67 | * Flycheck: Flycheck (1). 68 | 69 | @end detailmenu 70 | @end menu 71 | 72 | @node Installation 73 | @chapter Installation 74 | 75 | @menu 76 | * Brief and Generic Instructions:: 77 | * Detailed and Concrete Instructions:: 78 | * Instructions for Source-Based Use-Package:: 79 | @end menu 80 | 81 | @node Brief and Generic Instructions 82 | @section Brief and Generic Instructions 83 | 84 | First, install the dependencies of Lean4-Mode: 85 | @itemize 86 | @item 87 | @uref{https://lean-lang.org/lean4/doc/setup.html, Lean} (version 4) 88 | @item 89 | Emacs (version 27 or later) 90 | @item 91 | Emacs packages @uref{https://github.com/magnars/dash.el, Dash} (available on GNU-Elpa), @uref{https://emacs-lsp.github.io/lsp-mode, lsp-mode}, and 92 | @uref{https://github.com/magit/magit/blob/main/lisp/magit-section.el, Magit-Section} (available on Melpa) 93 | @end itemize 94 | 95 | Second, install Lean4-Mode itself: 96 | @itemize 97 | @item 98 | Clone the @uref{https://github.com/leanprover-community/lean4-mode, Git repository of Lean4-Mode}. 99 | @item 100 | In your @uref{https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html, Emacs initialization file}, add the path to that local 101 | repository to the @code{load-path} list. 102 | @end itemize 103 | 104 | @node Detailed and Concrete Instructions 105 | @section Detailed and Concrete Instructions 106 | 107 | Install Lean version 4. 108 | 109 | Install Emacs version 27 or later. 110 | 111 | Install the Emacs packages Dash, lsp-mode and Magit-Section. Dash is 112 | the only one of these packages that is available in the default @uref{https://elpa.gnu.org, GNU 113 | Elpa} package-archive. You can install the remaining packages either 114 | from source or from @uref{https://melpa.org/#/getting-started, Melpa} package-archive. For later approach, add 115 | the following to your Emacs initialization file 116 | (e.g. @samp{~/.emacs.d/init.el}): 117 | 118 | @lisp 119 | (require 'package) 120 | 121 | (add-to-list 'package-archives 122 | '("melpa" . "https://melpa.org/packages/")) 123 | 124 | (add-to-list 'package-selected-packages 'dash) 125 | (add-to-list 'package-selected-packages 'lsp-mode) 126 | (add-to-list 'package-selected-packages 'magit-section) 127 | 128 | (package-refresh-contents) 129 | (package-install-selected-packages 'no-confirm) 130 | @end lisp 131 | 132 | Clone the Git repository of Lean4-Mode: 133 | 134 | @example 135 | git clone https://github.com/leanprover-community/lean4-mode.git ~/path/to/lean4-mode 136 | @end example 137 | 138 | In your Emacs initialization file, add the path to your local 139 | Lean4-Mode repository to the @code{load-path} list: 140 | @lisp 141 | (add-to-list 'load-path "~/path/to/lean4-mode") 142 | @end lisp 143 | 144 | Lean4-Mode should now already be enabled when you open a file with 145 | @samp{.lean} extension. But you can optionally also already load 146 | Lean4-Mode on Emacs startup, e.g. in order to customize variables: 147 | @lisp 148 | (require 'lean4-mode) 149 | @end lisp 150 | 151 | @node Instructions for Source-Based Use-Package 152 | @section Instructions for Source-Based Use-Package 153 | 154 | If you use a source-based package-manager (e.g. @samp{package-vc.el}, 155 | Straight or Elpaca), then make sure to list the @samp{"data"} directory in 156 | your Lean4-Mode package recipe. 157 | 158 | If you use the @code{use-package} macro and intent to defer loading of 159 | packages in order to improve your Emacs startup time, then make sure 160 | to specify @code{lean4-mode} as a @samp{:command}. 161 | 162 | Following subsections show concrete examples. 163 | 164 | @menu 165 | * Native @samp{vc} (Emacs 30 or later):: 166 | * Doom-Emacs:: 167 | * Straight:: 168 | @end menu 169 | 170 | @node Native @samp{vc} (Emacs 30 or later) 171 | @subsection Native @samp{:vc} (Emacs 30 or later) 172 | 173 | GNU Emacs comes with @samp{use-package.el} built-in since version 29. And 174 | since version 30, it also comes with a built-in @samp{:vc} keyword for the 175 | @code{use-package} macro that utilizes @samp{package-vc.el} to install Emacs 176 | packages from remote source repositories. 177 | 178 | @lisp 179 | (require 'package) 180 | (add-to-list 'package-archives 181 | '("melpa" . "https://melpa.org/packages/")) 182 | (package-initialize) 183 | 184 | (use-package lean4-mode 185 | :commands lean4-mode 186 | :vc (:url "https://github.com/leanprover-community/lean4-mode.git" 187 | :rev :last-release 188 | ;; Or, if you prefer the bleeding edge version of Lean4-Mode: 189 | ;; :rev :newest 190 | )) 191 | @end lisp 192 | 193 | @node Doom-Emacs 194 | @subsection Doom-Emacs 195 | 196 | If you use Doom-Emacs, you can place the following code in your Doom 197 | initialization file: 198 | 199 | @lisp 200 | (package! lean4-mode 201 | :recipe (:host github 202 | :repo "leanprover-community/lean4-mode" 203 | :files ("*.el" "data"))) 204 | @end lisp 205 | 206 | @node Straight 207 | @subsection Straight 208 | 209 | If you use the Straight package manager through Use-Package, then 210 | place the following code in your Emacs initialization file: 211 | 212 | @lisp 213 | (use-package lean4-mode 214 | :commands lean4-mode 215 | :straight (lean4-mode :type git :host github 216 | :repo "leanprover-community/lean4-mode" 217 | :files ("*.el" "data"))) 218 | @end lisp 219 | 220 | @node Usage 221 | @chapter Usage 222 | 223 | If things are working correctly, you should see the word "Lean 4" in 224 | Emacs mode-line when you open a file with @samp{.lean} extension. Emacs 225 | will ask you to identify the @emph{project} this file belongs to. If you 226 | then type @samp{#check id}, the word @samp{#check} will be underlined, and 227 | hovering over it will show you the type of @code{id}. 228 | 229 | To view the proof state, run @code{lean4-toggle-info} (@samp{C-c C-i}). This 230 | will display the @samp{*Lean Goals*} buffer (like the Lean Info-View pane 231 | in VS-Code) in a separate window. 232 | 233 | @multitable {aaaaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} 234 | @headitem Key 235 | @tab Description 236 | @tab Command 237 | @item @samp{C-c C-k} 238 | @tab Echo the keystroke needed to input the symbol at point 239 | @tab @code{quail-show-key} 240 | @item @samp{C-c C-d} 241 | @tab Recompile and reload imports 242 | @tab @code{lean4-refresh-file-dependencies} 243 | @item @samp{C-c C-x} or @samp{C-c C-l} 244 | @tab Execute Lean in stand-alone mode 245 | @tab @code{lean4-std-exe} 246 | @item @samp{C-c C-p C-l} 247 | @tab Builds package with lake 248 | @tab @code{lean4-lake-build} 249 | @item @samp{C-c C-i} 250 | @tab Toggle Info-View which shows goals and errors at point 251 | @tab @code{lean4-toggle-info-buffer} 252 | @end multitable 253 | 254 | @menu 255 | * lsp-mode:: 256 | * Flycheck:: 257 | @end menu 258 | 259 | @node lsp-mode 260 | @section lsp-mode 261 | 262 | For key bindings from lsp-mode, see @uref{https://emacs-lsp.github.io/lsp-mode/page/keybindings/, its respective documentation} and 263 | note that not all capabilities are supported by Lean4-Mode. 264 | 265 | @node Flycheck 266 | @section Flycheck 267 | 268 | You may optionally use Lean4-Mode together with Flycheck. In that 269 | case, the mode-line will show @samp{FlyC:E/N}, indicating that there are 270 | @samp{E} number of errors and @samp{N} number of notes. Following keys will be 271 | available by default (via @code{flycheck-mode-map}): 272 | 273 | @multitable {aaaaaaaaa} {aaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaa} 274 | @headitem Key 275 | @tab Description 276 | @tab Command 277 | @item @samp{C-c ! n} 278 | @tab Go to next error 279 | @tab @code{flycheck-next-error} 280 | @item @samp{C-c ! p} 281 | @tab Go to previous error 282 | @tab @code{flycheck-previous-error} 283 | @end multitable 284 | 285 | @node Configuration 286 | @chapter Configuration 287 | 288 | @menu 289 | * lsp-mode: lsp-mode (1). 290 | * Flycheck: Flycheck (1). 291 | @end menu 292 | 293 | @node lsp-mode (1) 294 | @section lsp-mode 295 | 296 | If you want breadcrumbs of namespaces and sections to be shown in the 297 | header-line, set the user option @code{lsp-headerline-breadcrumb-enable} to 298 | @code{t}. 299 | 300 | @node Flycheck (1) 301 | @section Flycheck 302 | 303 | Flycheck is an optional but supported dependency of Lean4-Mode. If 304 | Flycheck is installed, lsp-mode and thus Lean4-Mode will by default 305 | use it. If you want to customize this behavior, e.g. if you'd like to 306 | use Emacs' built-in Flymake package instead of Flycheck while keeping 307 | later installed, then customize the @code{lsp-diagnostics-provider} user 308 | option accordingly. 309 | 310 | @node Common Pitfalls 311 | @chapter Common Pitfalls 312 | 313 | Lean4-Mode only supports version 4 of Lean. For editing Lean version 314 | 3, use @uref{https://github.com/leanprover/lean3-mode, Lean3-Mode}, which is also known as Lean-Mode due to historical 315 | reasons. In principle, it is fine to have both Lean3-Mode and 316 | Lean4-Mode installed at the same time. But note that Lean3-Mode uses 317 | the prefix @samp{lean-} for its symbols. E.g. you should not use 318 | @samp{lean-}-prefixed commands in a buffer with Lean4-Mode as major mode. 319 | 320 | @bye 321 | -------------------------------------------------------------------------------- /lean4-settings.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-settings.el --- Lean4-Mode User-Options -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2014 Microsoft Corporation. All rights reserved. 4 | 5 | ;; This file is not part of GNU Emacs. 6 | 7 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 8 | ;; may not use this file except in compliance with the License. You 9 | ;; may obtain a copy of the License at 10 | ;; 11 | ;; http://www.apache.org/licenses/LICENSE-2.0 12 | ;; 13 | ;; Unless required by applicable law or agreed to in writing, software 14 | ;; distributed under the License is distributed on an "AS IS" BASIS, 15 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 16 | ;; implied. See the License for the specific language governing 17 | ;; permissions and limitations under the License. 18 | 19 | ;;; Commentary: 20 | 21 | ;; This library defines custom variables for `lean4-mode'. 22 | 23 | ;;; Code: 24 | 25 | (require 'cl-lib) 26 | (require 'lsp-mode) 27 | 28 | (defgroup lean4 nil 29 | "Major mode for Lean4 programming language and theorem prover." 30 | :group 'languages 31 | :link '(info-link :tag "Info Manual" "(lean4-mode)") 32 | :link '(url-link 33 | :tag "Website" 34 | "https://github.com/leanprover-community/lean4-mode") 35 | :link '(emacs-library-link :tag "Library Source" "lean4-mode.el") 36 | :prefix "lean4-") 37 | 38 | (defgroup lean4-keybinding nil 39 | "Keybindings for lean4-mode." 40 | :prefix "lean4-" 41 | :group 'lean4) 42 | 43 | (defconst lean4-default-executable-name 44 | (cl-case system-type 45 | (windows-nt "lean.exe") 46 | (t "lean")) 47 | "Default executable name of Lean.") 48 | 49 | (defconst lean4-default-lake-name 50 | (cl-case system-type 51 | (windows-nt "lake.exe") 52 | (t "lake")) 53 | "Default executable name of Lake.") 54 | 55 | (defcustom lean4-mode-hook (list #'lsp) 56 | "Hook run after entering `lean4-mode'." 57 | :options '(flycheck-mode lsp) 58 | :type 'hook 59 | :group 'lean4) 60 | 61 | (defcustom lean4-rootdir nil 62 | "Full pathname of lean root directory. It should be defined by user." 63 | :group 'lean4 64 | :type 'string) 65 | 66 | (defcustom lean4-executable-name lean4-default-executable-name 67 | "Name of lean executable." 68 | :group 'lean4 69 | :type 'string) 70 | 71 | (defcustom lean4-lake-name lean4-default-lake-name 72 | "Name of lake executable." 73 | :group 'lake 74 | :type 'string) 75 | 76 | (defcustom lean4-memory-limit 1024 77 | "Memory limit for lean process in megabytes." 78 | :group 'lean4 79 | :type 'number) 80 | 81 | (defcustom lean4-timeout-limit 100000 82 | "Deterministic timeout limit. 83 | 84 | It is approximately the maximum number of memory allocations in thousands." 85 | :group 'lean4 86 | :type 'number) 87 | 88 | (defcustom lean4-extra-arguments nil 89 | "Extra command-line arguments to the lean process." 90 | :group 'lean4 91 | :type '(list string)) 92 | 93 | (defcustom lean4-delete-trailing-whitespace nil 94 | "Automatically delete trailing shitespace. 95 | Set this variable to true to automatically delete trailing 96 | whitespace when a buffer is loaded from a file or when it is 97 | written." 98 | :group 'lean4 99 | :type 'boolean) 100 | 101 | (defcustom lean4-highlight-inaccessible-names t 102 | "Use font to highlight inaccessible names. 103 | Set this variable to t to highlight inaccessible names in the info display 104 | using `font-lock-comment-face' instead of the `✝` suffix used by Lean." 105 | :group 'lean4 106 | :type 'boolean) 107 | 108 | (defcustom lean4-show-file-progress t 109 | "Highlight file progress in the current buffer." 110 | :group 'lean4 111 | :type 'boolean) 112 | 113 | 114 | (defcustom lean4-autodetect-lean3 nil 115 | "Autodetect Lean version. 116 | Use elan to check if current project uses Lean 3 or Lean 4 and initialize the 117 | right mode when visiting a file. If elan has a default Lean version, Lean files 118 | outside a project will default to that mode." 119 | :group 'lean4 120 | :type 'boolean) 121 | 122 | (defcustom lean4-keybinding-std-exe1 (kbd "C-c C-x") 123 | "Main Keybinding for `lean4-std-exe'." 124 | :group 'lean4-keybinding :type 'key-sequence) 125 | (defcustom lean4-keybinding-std-exe2 (kbd "C-c C-l") 126 | "Alternative Keybinding for `lean4-std-exe'." 127 | :group 'lean4-keybinding :type 'key-sequence) 128 | (defcustom lean4-keybinding-show-key (kbd "C-c C-k") 129 | "Lean Keybinding for `quail-show-key'." 130 | :group 'lean4-keybinding :type 'key-sequence) 131 | (defcustom lean4-keybinding-server-restart (kbd "C-c C-r") 132 | "Lean Keybinding for server-restart." 133 | :group 'lean4-keybinding :type 'key-sequence) 134 | (defcustom lean4-keybinding-tab-indent (kbd "TAB") 135 | "Lean Keybinding for `lean4-tab-indent'." 136 | :group 'lean4-keybinding :type 'key-sequence) 137 | (defcustom lean4-keybinding-auto-complete (kbd "S-SPC") 138 | "Lean Keybinding for auto completion." 139 | :group 'lean4-keybinding :type 'key-sequence) 140 | (defcustom lean4-keybinding-lean4-toggle-info (kbd "C-c C-i") 141 | "Lean Keybinding for `lean4-toggle-info'." 142 | :group 'lean4-keybinding :type 'key-sequence) 143 | (defcustom lean4-keybinding-lake-build (kbd "C-c C-p C-l") 144 | "Lean Keybinding for `lean4-lake-build'." 145 | :group 'lean4-keybinding :type 'key-sequence) 146 | (defcustom lean4-keybinding-refresh-file-dependencies (kbd "C-c C-d") 147 | "Lean Keybinding for `lean4-refresh-file-dependencies'." 148 | :group 'lean4-keybinding :type 'key-sequence) 149 | 150 | (provide 'lean4-settings) 151 | ;;; lean4-settings.el ends here 152 | -------------------------------------------------------------------------------- /lean4-syntax.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-syntax.el --- Lean4-Mode Syntax Definitions -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2013, 2014 Microsoft Corporation. All rights reserved. 4 | 5 | ;; This file is not part of GNU Emacs. 6 | 7 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 8 | ;; may not use this file except in compliance with the License. You 9 | ;; may obtain a copy of the License at 10 | ;; 11 | ;; http://www.apache.org/licenses/LICENSE-2.0 12 | ;; 13 | ;; Unless required by applicable law or agreed to in writing, software 14 | ;; distributed under the License is distributed on an "AS IS" BASIS, 15 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 16 | ;; implied. See the License for the specific language governing 17 | ;; permissions and limitations under the License. 18 | 19 | ;;; Commentary: 20 | 21 | ;; This library defines syntaxes for `lean4-mode'. 22 | 23 | ;;; Code: 24 | 25 | (require 'dash) 26 | (require 'rx) 27 | 28 | (defconst lean4-keywords1 29 | '("import" "prelude" "protected" "private" "noncomputable" 30 | "unsafe" "partial" "renaming" "hiding" "begin" "constant" 31 | "variable" "variables" "theorem" "example" "abbrev" 32 | "open" "export" "axiom" "inductive" "with" 33 | "structure" "universe" "universes" "hide" 34 | "precedence" "match_syntax" "match" "nomatch" "infix" "infixl" "infixr" "notation" "postfix" "prefix" "instance" 35 | "end" "this" "using" "using_well_founded" "namespace" "section" 36 | "attribute" "local" "set_option" "extends" "include" "class" 37 | "attributes" "raw" "have" "show" "suffices" "by" "in" "at" "do" "let" "for" "unless" "break" "continue" 38 | "try" "catch" "finally" "where" "rec" "mut" "forall" "fun" 39 | "exists" "if" "then" "else" "from" "init_quot" "return" 40 | "mutual" "def" "run_cmd" "declare_syntax_cat" "syntax" "macro_rules" "macro" "scoped" "elab" 41 | "initialize" "builtin_initialize" "register_builtin_option" "induction" "cases" "generalizing" "unif_hint" "deriving") 42 | "Lean keywords ending with `word' (not symbol).") 43 | (defconst lean4-keywords1-regexp 44 | (eval `(rx word-start (or ,@lean4-keywords1) word-end))) 45 | (defconst lean4-constants 46 | '("#" "@" "!" "$" "->" "∼" "↔" "/" "==" "=" ":=" "<->" "/\\" "\\/" "∧" "∨" 47 | "≠" "<" ">" "≤" "≥" "¬" "<=" ">=" "⁻¹" "⬝" "▸" "+" "*" "-" "/" "λ" 48 | "→" "∃" "∀" "∘" "×" "Σ" "Π" "~" "||" "&&" "≃" "≡" "≅" 49 | "ℕ" "ℤ" "ℚ" "ℝ" "ℂ" "𝔸" 50 | "⬝e" "⬝i" "⬝o" "⬝op" "⬝po" "⬝h" "⬝v" "⬝hp" "⬝vp" "⬝ph" "⬝pv" "⬝r" "◾" "◾o" 51 | "∘n" "∘f" "∘fi" "∘nf" "∘fn" "∘n1f" "∘1nf" "∘f1n" "∘fn1" 52 | "^c" "≃c" "≅c" "×c" "×f" "×n" "+c" "+f" "+n" "ℕ₋₂") 53 | "Lean constants.") 54 | (defconst lean4-constants-regexp (regexp-opt lean4-constants)) 55 | (defconst lean4-numerals-regexp 56 | (eval `(rx word-start 57 | (one-or-more digit) (optional (and "." (zero-or-more digit))) 58 | word-end))) 59 | 60 | (defconst lean4-warnings '("sorry") "Lean warnings.") 61 | (defconst lean4-warnings-regexp 62 | (eval `(rx word-start (or ,@lean4-warnings) word-end))) 63 | (defconst lean4-debugging '("unreachable!" "panic!" "assert!" "dbg_trace") "Lean debugging.") 64 | (defconst lean4-debugging-regexp 65 | (eval `(rx word-start (or ,@lean4-debugging) word-end))) 66 | 67 | 68 | (defconst lean4-syntax-table 69 | (let ((st (make-syntax-table))) 70 | ;; Matching parens 71 | (modify-syntax-entry ?\[ "(]" st) 72 | (modify-syntax-entry ?\] ")[" st) 73 | (modify-syntax-entry ?\{ "(}" st) 74 | (modify-syntax-entry ?\} "){" st) 75 | 76 | ;; comment 77 | (modify-syntax-entry ?/ ". 14nb" st) 78 | (modify-syntax-entry ?- ". 123" st) 79 | (modify-syntax-entry ?\n ">" st) 80 | (modify-syntax-entry ?« "<" st) 81 | (modify-syntax-entry ?» ">" st) 82 | 83 | ;; Word constituent 84 | (--each (list ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m 85 | ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z 86 | ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M 87 | ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z) 88 | (modify-syntax-entry it "w" st)) 89 | (--each (list ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9) 90 | (modify-syntax-entry it "w" st)) 91 | (--each (list ?α ?β ?γ ?δ ?ε ?ζ ?η ?θ ?ι ?κ ;;?λ 92 | ?μ ?ν ?ξ ?ο ?π ?ρ ?ς ?σ ?τ ?υ 93 | ?φ ?χ ?ψ ?ω) 94 | (modify-syntax-entry it "w" st)) 95 | (--each (list ?ϊ ?ϋ ?ό ?ύ ?ώ ?Ϗ ?ϐ ?ϑ ?ϒ ?ϓ ?ϔ ?ϕ ?ϖ 96 | ?ϗ ?Ϙ ?ϙ ?Ϛ ?ϛ ?Ϝ ?ϝ ?Ϟ ?ϟ ?Ϡ ?ϡ ?Ϣ ?ϣ 97 | ?Ϥ ?ϥ ?Ϧ ?ϧ ?Ϩ ?ϩ ?Ϫ ?ϫ ?Ϭ ?ϭ ?Ϯ ?ϯ ?ϰ 98 | ?ϱ ?ϲ ?ϳ ?ϴ ?ϵ ?϶ ?Ϸ ?ϸ ?Ϲ ?Ϻ ?ϻ) 99 | (modify-syntax-entry it "w" st)) 100 | (--each (list ?ἀ ?ἁ ?ἂ ?ἃ ?ἄ ?ἅ ?ἆ ?ἇ ?Ἀ ?Ἁ ?Ἂ ?Ἃ ?Ἄ 101 | ?Ἅ ?Ἆ ?Ἇ ?ἐ ?ἑ ?ἒ ?ἓ ?ἔ ?ἕ ?἖ ?἗ ?Ἐ ?Ἑ 102 | ?Ἒ ?Ἓ ?Ἔ ?Ἕ ?἞ ?἟ ?ἠ ?ἡ ?ἢ ?ἣ ?ἤ ?ἥ 103 | ?ἦ ?ἧ ?Ἠ ?Ἡ ?Ἢ ?Ἣ ?Ἤ ?Ἥ ?Ἦ ?Ἧ ?ἰ ?ἱ 104 | ?ἲ ?ἳ ?ἴ ?ἵ ?ἶ ?ἷ ?Ἰ ?Ἱ ?Ἲ ?Ἳ ?Ἴ ?Ἵ ?Ἶ ?Ἷ 105 | ?ὀ ?ὁ ?ὂ ?ὃ ?ὄ ?ὅ ?὆ ?὇ ?Ὀ ?Ὁ ?Ὂ ?Ὃ 106 | ?Ὄ ?Ὅ ?὎ ?὏ ?ὐ ?ὑ ?ὒ ?ὓ ?ὔ ?ὕ ?ὖ ?ὗ 107 | ?὘ ?Ὑ ?὚ ?Ὓ ?὜ ?Ὕ ?὞ ?Ὗ ?ὠ ?ὡ ?ὢ 108 | ?ὣ ?ὤ ?ὥ ?ὦ ?ὧ ?Ὠ ?Ὡ ?Ὢ ?Ὣ ?Ὤ ?Ὥ ?Ὦ 109 | ?Ὧ ?ὰ ?ά ?ὲ ?έ ?ὴ ?ή ?ὶ ?ί ?ὸ ?ό ?ὺ ?ύ ?ὼ 110 | ?ώ ?὾ ?὿ ?ᾀ ?ᾁ ?ᾂ ?ᾃ ?ᾄ ?ᾅ ?ᾆ ?ᾇ ?ᾈ 111 | ?ᾉ ?ᾊ ?ᾋ ?ᾌ ?ᾍ ?ᾎ ?ᾏ ?ᾐ ?ᾑ ?ᾒ ?ᾓ ?ᾔ 112 | ?ᾕ ?ᾖ ?ᾗ ?ᾘ ?ᾙ ?ᾚ ?ᾛ ?ᾜ ?ᾝ ?ᾞ ?ᾟ ?ᾠ ?ᾡ ?ᾢ 113 | ?ᾣ ?ᾤ ?ᾥ ?ᾦ ?ᾧ ?ᾨ ?ᾩ ?ᾪ ?ᾫ ?ᾬ ?ᾭ ?ᾮ ?ᾯ ?ᾰ 114 | ?ᾱ ?ᾲ ?ᾳ ?ᾴ ?᾵ ?ᾶ ?ᾷ ?Ᾰ ?Ᾱ ?Ὰ ?Ά ?ᾼ ?᾽ 115 | ?ι ?᾿ ?῀ ?῁ ?ῂ ?ῃ ?ῄ ?῅ ?ῆ ?ῇ ?Ὲ ?Έ ?Ὴ 116 | ?Ή ?ῌ ?῍ ?῎ ?῏ ?ῐ ?ῑ ?ῒ ?ΐ ?῔ ?῕ ?ῖ ?ῗ 117 | ?Ῐ ?Ῑ ?Ὶ ?Ί ?῜ ?῝ ?῞ ?῟ ?ῠ ?ῡ ?ῢ ?ΰ ?ῤ ?ῥ 118 | ?ῦ ?ῧ ?Ῠ ?Ῡ ?Ὺ ?Ύ ?Ῥ ?῭ ?΅ ?` ?῰ ?῱ ?ῲ ?ῳ 119 | ?ῴ ?῵ ?ῶ ?ῷ ?Ὸ ?Ό ?Ὼ ?Ώ ?ῼ ?´ ?῾) 120 | (modify-syntax-entry it "w" st)) 121 | (--each (list ?℀ ?℁ ?ℂ ?℃ ?℄ ?℅ ?℆ ?ℇ ?℈ ?℉ ?ℊ ?ℋ ?ℌ ?ℍ ?ℎ 122 | ?ℏ ?ℐ ?ℑ ?ℒ ?ℓ ?℔ ?ℕ ?№ ?℗ ?℘ ?ℙ ?ℚ ?ℛ ?ℜ ?ℝ 123 | ?℞ ?℟ ?℠ ?℡ ?™ ?℣ ?ℤ ?℥ ?Ω ?℧ ?ℨ ?℩ ?K ?Å ?ℬ 124 | ?ℭ ?℮ ?ℯ ?ℰ ?ℱ ?Ⅎ ?ℳ ?ℴ ?ℵ ?ℶ ?ℷ ?ℸ ?ℹ ?℺ ?℻ 125 | ?ℼ ?ℽ ?ℾ ?ℿ ?⅀ ?⅁ ?⅂ ?⅃ ?⅄ ?ⅅ ?ⅆ ?ⅇ ?ⅈ ?ⅉ ?⅊ 126 | ?⅋ ?⅌ ?⅍ ?ⅎ ?⅏) 127 | (modify-syntax-entry it "w" st)) 128 | (--each (list ?₁ ?₂ ?₃ ?₄ ?₅ ?₆ ?₇ ?₈ ?₉ ?₀ 129 | ?ₐ ?ₑ ?ₒ ?ₓ ?ₔ ?ₕ ?ₖ ?ₗ ?ₘ ?ₙ ?ₚ ?ₛ ?ₜ 130 | ?' ?_ ?! ??) 131 | (modify-syntax-entry it "w" st)) 132 | 133 | ;; Lean operator chars 134 | (--each (string-to-list "#$%&*+<=>@^|~:") 135 | (modify-syntax-entry it "." st)) 136 | 137 | ;; Whitespace is whitespace 138 | (modify-syntax-entry ?\ " " st) 139 | (modify-syntax-entry ?\t " " st) 140 | 141 | ;; Strings 142 | (modify-syntax-entry ?\" "\"" st) 143 | (modify-syntax-entry ?\\ "/" st) 144 | 145 | st)) 146 | 147 | (defconst lean4-font-lock-defaults 148 | `((;; attributes 149 | (,(rx word-start "attribute" word-end (zero-or-more whitespace) (group (one-or-more "[" (zero-or-more (not (any "]"))) "]" (zero-or-more whitespace)))) 150 | (1 'font-lock-preprocessor-face)) 151 | (,(rx (group "@[" (zero-or-more (not (any "]"))) "]")) 152 | (1 'font-lock-preprocessor-face)) 153 | (,(rx (group "#" (or "eval" "print" "reduce" "help" "check" "lang" "check_failure" "synth"))) 154 | (1 'font-lock-keyword-face)) 155 | ;; mutual definitions "names" 156 | (,(rx word-start 157 | "mutual" 158 | word-end 159 | (zero-or-more whitespace) 160 | word-start 161 | (or "inductive" "definition" "def") 162 | word-end 163 | (group (zero-or-more (not (any " \t\n\r{([,"))) (zero-or-more (zero-or-more whitespace) "," (zero-or-more whitespace) (not (any " \t\n\r{([,"))))) 164 | (1 'font-lock-function-name-face)) 165 | ;; declarations 166 | (,(rx word-start 167 | (group (or "inductive" (group "class" (zero-or-more whitespace) "inductive") "instance" "structure" "class" "theorem" "axiom" "lemma" "definition" "def" "constant")) 168 | word-end (zero-or-more whitespace) 169 | (group (zero-or-more "{" (zero-or-more (not (any "}"))) "}" (zero-or-more whitespace))) 170 | (zero-or-more whitespace) 171 | (group (zero-or-more (not (any " \t\n\r{(["))))) 172 | (4 'font-lock-function-name-face)) 173 | ;; Constants which have a keyword as subterm 174 | (,(rx (or "∘if")) . 'font-lock-constant-face) 175 | ;; Keywords 176 | ("\\(set_option\\)[ \t]*\\([^ \t\n]*\\)" (2 'font-lock-constant-face)) 177 | (,lean4-keywords1-regexp . 'font-lock-keyword-face) 178 | (,(rx word-start (group "example") ".") (1 'font-lock-keyword-face)) 179 | (,(rx (or "∎")) . 'font-lock-keyword-face) 180 | ;; Types 181 | (,(rx word-start (or "Prop" "Type" "Type*" "Sort" "Sort*") symbol-end) . 'font-lock-type-face) 182 | (,(rx word-start (group (or "Prop" "Type" "Sort")) ".") (1 'font-lock-type-face)) 183 | ;; String 184 | ("\"[^\"]*\"" . 'font-lock-string-face) 185 | ;; Debugging builtins 186 | (,lean4-debugging-regexp . 'font-lock-warning-face) 187 | ;; ;; Constants 188 | (,lean4-constants-regexp . 'font-lock-constant-face) 189 | (,lean4-numerals-regexp . 'font-lock-constant-face) 190 | ;; place holder 191 | (,(rx symbol-start "_" symbol-end) . 'font-lock-preprocessor-face) 192 | ;; warnings 193 | (,lean4-warnings-regexp . 'font-lock-warning-face) 194 | ;; escaped identifiers 195 | (,(rx (and (group "«") (group (one-or-more (not (any "»")))) (group "»"))) 196 | (1 font-lock-comment-face t) 197 | (2 nil t) 198 | (3 font-lock-comment-face t))))) 199 | 200 | ;; Syntax Highlighting for Lean Info Mode 201 | (defconst lean4-info-font-lock-defaults 202 | (let ((new-entries 203 | `(;; Please add more after this: 204 | (,(rx (group (+ symbol-start (+ (or word (char ?₁ ?₂ ?₃ ?₄ ?₅ ?₆ ?₇ ?₈ ?₉ ?₀))) symbol-end (* white))) ":") 205 | (1 'font-lock-variable-name-face)) 206 | (,(rx white ":" white) 207 | . 'font-lock-keyword-face) 208 | (,(rx "⊢" white) 209 | . 'font-lock-keyword-face) 210 | (,(rx "[" (group "stale") "]") 211 | (1 'font-lock-warning-face)) 212 | (,(rx line-start "No Goal" line-end) 213 | . 'font-lock-constant-face))) 214 | (inherited-entries (car lean4-font-lock-defaults))) 215 | `(,(-concat new-entries inherited-entries)))) 216 | 217 | (provide 'lean4-syntax) 218 | ;;; lean4-syntax.el ends here 219 | -------------------------------------------------------------------------------- /lean4-util.el: -------------------------------------------------------------------------------- 1 | ;;; lean4-util.el --- Lean4-Mode Utilities -*- lexical-binding: t; -*- 2 | 3 | ;; Copyright (c) 2014 Microsoft Corporation. All rights reserved. 4 | 5 | ;; This file is not part of GNU Emacs. 6 | 7 | ;; Licensed under the Apache License, Version 2.0 (the "License"); you 8 | ;; may not use this file except in compliance with the License. You 9 | ;; may obtain a copy of the License at 10 | ;; 11 | ;; http://www.apache.org/licenses/LICENSE-2.0 12 | ;; 13 | ;; Unless required by applicable law or agreed to in writing, software 14 | ;; distributed under the License is distributed on an "AS IS" BASIS, 15 | ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 16 | ;; implied. See the License for the specific language governing 17 | ;; permissions and limitations under the License. 18 | 19 | ;;; Commentary: 20 | 21 | ;; This library provides utilities for `lean4-mode'. 22 | 23 | ;;; Code: 24 | 25 | (require 'compat) 26 | (require 'lean4-settings) 27 | 28 | (defun lean4-setup-rootdir () 29 | "Search for lean executable in variable `exec-path'. 30 | Try to find an executable named `lean4-executable-name' in variable `exec-path'. 31 | On succsess, return path to the directory with this executable." 32 | (let ((root (executable-find lean4-executable-name))) 33 | (when root 34 | (setq lean4-rootdir (file-name-directory 35 | (directory-file-name 36 | (file-name-directory root))))) 37 | lean4-rootdir)) 38 | 39 | (defun lean4-get-rootdir () 40 | "Search for lean executable in `lean4-rootdir' and variable `exec-path'. 41 | First try to find an executable named `lean4-executable-name' in 42 | `lean4-rootdir'. On failure, search in variable `exec-path'." 43 | (if lean4-rootdir 44 | (let ((lean4-path (expand-file-name lean4-executable-name (expand-file-name "bin" lean4-rootdir)))) 45 | (unless (file-exists-p lean4-path) 46 | (error "Incorrect `lean4-rootdir' value, path '%s' does not exist" lean4-path)) 47 | lean4-rootdir) 48 | (or 49 | (lean4-setup-rootdir) 50 | (error 51 | (concat "Lean was not found in the `exec-path' and `lean4-rootdir' is not defined. " 52 | "Please set it via M-x customize-variable RET lean4-rootdir RET."))))) 53 | 54 | (defun lean4-get-executable (exe-name) 55 | "Return fullpath of lean executable EXE-NAME." 56 | (file-name-concat (lean4-get-rootdir) "bin" exe-name)) 57 | 58 | (defun lean4-whitespace-cleanup () 59 | "Delete trailing whitespace if `lean4-delete-trailing-whitespace' is t." 60 | (when lean4-delete-trailing-whitespace 61 | (delete-trailing-whitespace))) 62 | 63 | (provide 'lean4-util) 64 | ;;; lean4-util.el ends here 65 | --------------------------------------------------------------------------------