├── .editorconfig ├── .git-blame-ignore-revs ├── .gitattributes ├── .gitconfig ├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── nix.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── MAINTAINERS.txt ├── README.md ├── after └── syntax │ └── purescript.vim ├── doc └── purescript-vim.txt ├── flake.lock ├── flake.nix ├── ftdetect └── purescript.vim ├── ftplugin └── purescript.vim ├── generate-doc.sh ├── indent └── purescript.vim └── syntax └── purescript.vim /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.vim] 12 | indent_style = tab 13 | 14 | # matches other purescript-contrib projects 15 | [*.{md,yml}] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [CHANGELOG.md] 20 | indent_size = unset 21 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # This file contains a list of commits that are not likely what you 2 | # are looking for in a blame, such as mass reformatting or renaming. 3 | # You can set this file as a default ignore file for blame by running 4 | # the following command. 5 | # 6 | # $ git config blame.ignoreRevsFile .git-blame-ignore-revs 7 | # 8 | # To temporarily not use this file add 9 | # --ignore-revs-file="" 10 | # to your blame command. 11 | 12 | # EditorConfig settings applied 13 | 4177244a99b17de647f94da51ca01fb2ded69d2b 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [blame] 2 | ignoreRevsFile = .git-blame-ignore-revs 3 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Checklist:** 2 | 3 | - [ ] Briefly described the change 4 | - [ ] Opened an issue before investing a significant amount of work into changes 5 | - [ ] Updated README.md with any new configuration options and behavior 6 | - [ ] Updated CHANGELOG.md with the proposed changes 7 | - [ ] Ran `generate-doc.sh` to re-generate the documentation 8 | -------------------------------------------------------------------------------- /.github/workflows/nix.yml: -------------------------------------------------------------------------------- 1 | name: Nix 2 | on: [ push ] 3 | 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v3 9 | with: 10 | # Nix Flakes doesn’t work on shallow clones 11 | fetch-depth: 0 12 | - uses: cachix/install-nix-action@v18 13 | with: 14 | nix_path: nixpkgs=channel:nixos-unstable 15 | - run: echo "experimental-features = nix-command flakes" | sudo tee -a /etc/nix/nix.conf 16 | - run: nix flake check 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # You’re using the wrong editor ;) 2 | .vscode/ 3 | *.code-workspace 4 | 5 | # …But even with the correct one, we all make errors 6 | *.sw[opq] 7 | :wq?a? 8 | :x 9 | 10 | # Environmental tools 11 | result*/ 12 | .direnv/ 13 | .envrc 14 | 15 | # OS generated files 16 | .DS_Store 17 | .DS_Store? 18 | ._* 19 | .Spotlight-V100 20 | .Trashes 21 | Icon? 22 | ehthumbs.db 23 | Thumbs.db 24 | .Trash* 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 4 | 5 | ## [Unreleased] 6 | 7 | Breaking changes (😱!!!): 8 | - use `-- %s` instead of `{--%s--}` for comments [p68][] 9 | 10 | New features: 11 | - add Vim manual (`:help purescript-vim`) [p73][] 12 | - add setting to disable indentation (`let g:purescript_disable_indent = 1`) [p75][] 13 | - highlight TODO/FIXME/XXX in comments [p76][] 14 | - additional TODO highlighting in comments [p81][] 15 | - allow folds on imports [p83][] 16 | - add Unicode symbol conceal (`let g:purescript_unicode_conceal_enable = 1`) [p87][] 17 | 18 | Bugfixes: 19 | - docs did not reflect the code in using the `g:` prefix for indentation configuration [p73][] 20 | - some Unicode characters were not accounted for for the indentation [p84][] 21 | - highlight all bicameral scripts, not just Latin ones [p85][] 22 | 23 | Other improvements: 24 | - rename default branch to `main`, clarify readme, add changelog [p73][] 25 | - add install instruction for Vim 8 packages 26 | - add tooling to lint the project 27 | - add `MAINTAINERS.txt` 28 | 29 | ## [v1.0.0](https://github.com/purescript-contrib/purescript-vim/releases/tag/v1.0.0) - 2017-10-19 30 | 31 | Syntax issues (#35) 32 | 33 | * syntax 34 | 35 | * add purescriptClassDecl region 36 | - import class 37 | - class statement 38 | - higlight class keyword and class name 39 | * higlight instances 40 | 41 | Issues: #22, #23 42 | 43 | * remove commented code 44 | 45 | * Indent (#44) 46 | 47 | * indent class and remove '|' from operator characters 48 | 49 | If '|' was included then there is extra indent in 50 | ``` 51 | class RowLacking (entry :: Type) 52 | (key :: Symbol) 53 | (typ :: Type) 54 | (row :: # Type) | 55 | >> 56 | entry typ -> key row 57 | ``` 58 | 59 | * indent pattern guards 60 | 61 | * guard against class 62 | * if the previous line contains `| otherwise` find the first line that 63 | does not start with `|` (actually find the first line that starts with 64 | `\k`, '^\%(\s*|\)\@!' did not work inside indent function for some 65 | reason. 66 | 67 | * Fixed #48 68 | 69 | * Fixed #49 70 | 71 | [p68][https://github.com/purescript-contrib/purescript-vim/pull/70] 72 | [p73][https://github.com/purescript-contrib/purescript-vim/pull/73] 73 | [p75][https://github.com/purescript-contrib/purescript-vim/pull/75] 74 | [p76][https://github.com/purescript-contrib/purescript-vim/pull/76] 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to purescript-vim 2 | 3 | Thanks for your interest in contributing to `purescript-vim`! We welcome new contributions regardless of your level of experience or familiarity with PureScript or VimL. 4 | 5 | Every library in the Contributors organization shares a simple handbook that helps new contributors get started. With that in mind, please [read the short contributing guide on purescript-contrib/governance](https://github.com/purescript-contrib/governance/blob/main/contributing.md) before contributing to this library. 6 | 7 | ## Preparing a pull request or patch 8 | 9 | [Pull requests](https://github.com/purescript-contrib/purescript-vim/pulls) may be opened on the primary Git forge. If you do not have a Microsoft GitHub account or would prefer, there is also a [mailing list](https://lists.sr.ht/~toastal/purescript-vim) that can be used with [`git send-email`](https://git-send-email.io). 10 | 11 | Patches/pull request checklist: 12 | 13 | - [ ] Opened an [issue](https://github.com/purescript-contrib/purescript-aff/issues) or posted to the [mailing list](https://lists.sr.ht/~toastal/purescript-vim) before investing a significant amount of work into changes 14 | - [ ] Update README.md with any new configuration options and behavior 15 | - [ ] Update CHANGELOG.md with the proposed changes 16 | - [ ] Run `./generate-doc.sh` to re-generate the documentation (requires [`npx`](https://www.npmjs.com/package/npx) which can be gotten from Nix shell) 17 | - [ ] Run linters via `nix flake check` 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 raichoo 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /MAINTAINERS.txt: -------------------------------------------------------------------------------- 1 | Currently active maintainers 2 | ---------------------------- 3 | 4 | toastal 5 | E-mail: toastal@posteo.net 6 | PGP fingerprint: 7944 74B7 D236 DAB9 C9EF E7F9 5CCE 6F14 66D4 7C9E 7 | GitHub ID: 561087 8 | Matrix: @toastal:matrix.org 9 | IRC: @toastal:libera.chat 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # purescript-vim 2 | 3 | [PureScript][] language support for Vim and Neovim providing syntax highlighting and indentation based on based on [idris-vim][] and [haskell-vim][]. 4 | 5 | See [purescript-language-server][] for details on how to set up language server support for [PureScript][]. 6 | 7 | ## License 8 | 9 | This project is licensed under The 2-Clause BSD License ([BSD-2-Clause](https://opensource.org/licenses/BSD-2-Clause)) — see the LICENSE file in this project for details. 10 | 11 | ## Installation 12 | 13 | ### Manual Installation (no plugin manager) 14 | 15 | Copy content of this repository into your `~/.vim` directory (or `%HOME%\vimfiles` on Windows). 16 | 17 | Be sure that the following lines are in your `.vimrc` 18 | ```vim 19 | syntax on 20 | filetype on 21 | filetype plugin indent on 22 | ``` 23 | 24 | ### Vim 8 packages 25 | 26 | If you have Vim version 8 (`vim --version | head -n1`), you can install plugins with the native pack system: 27 | 28 | ```sh-session 29 | $ mkdir -p ~/.vim/pack/plugins/start/ 30 | $ cd ~/.vim/pack/plugins/start/ 31 | $ git clone https://github.com/purescript-contrib/purescript-vim.git 32 | ``` 33 | 34 | ### Pathogen 35 | 36 | If you are using [Pathogen][], clone this repo into your `~/.vim/bundle` directory and you are ready to go. 37 | 38 | ```sh-session 39 | $ cd ~/.vim/bundle 40 | $ git clone https://github.com/purescript-contrib/purescript-vim.git 41 | ``` 42 | ### vim-plug 43 | 44 | If you are using [vim-plug][], add the following line in between your `plug#begin` and `plug#end` calls for your Vim config file: 45 | 46 | ```vim 47 | Plug 'purescript-contrib/purescript-vim' 48 | ``` 49 | 50 | Save and restart (Neo)Vim and run `:PlugInstall`. 51 | 52 | ## Configuration 53 | 54 | ### Indentation 55 | 56 | To configure indentation in `purescript-vim` you can use the following variables: 57 | 58 | #### g:purescript_disable_indent 59 | 60 | Disable indentation altogether. 61 | 62 | ```vim 63 | let g:purescript_disable_indent = 1 64 | ``` 65 | 66 | #### g:purescript_indent_case 67 | 68 | ```vim 69 | let g:purescript_indent_case = 5 70 | ``` 71 | 72 | ```purescript 73 | case xs of 74 | >>>>>[] -> ... 75 | >>>>>(y:ys) -> ... 76 | ``` 77 | 78 | #### g:purescript_indent_let 79 | 80 | ```vim 81 | let g:purescript_indent_let = 4 82 | ``` 83 | 84 | ```purescript 85 | let x = 0 in 86 | >>>>x 87 | ``` 88 | 89 | #### g:purescript_indent_in 90 | 91 | ```vim 92 | let g:purescript_indent_in = 1 93 | ``` 94 | 95 | ```purescript 96 | let x = 0 97 | >in x 98 | ``` 99 | 100 | #### g:purescript_indent_where 101 | 102 | ```vim 103 | let g:purescript_indent_where = 6 104 | ``` 105 | 106 | ```purescript 107 | where f :: Int -> Int 108 | >>>>>>f x = x 109 | ``` 110 | 111 | #### g:purescript_indent_do 112 | 113 | ```vim 114 | let g:purescript_indent_do = 3 115 | ``` 116 | 117 | ```purescript 118 | do x <- a 119 | >>>y <- b 120 | ``` 121 | 122 | #### g:purescript_indent_dot 123 | 124 | ```vim 125 | let g:purescript_indent_dot = 1 126 | ``` 127 | 128 | ```purescript 129 | unsnoc 130 | :: forall a 131 | >. List a 132 | -> Maybe (List a, a) 133 | ``` 134 | 135 | ## Unicode conceal 136 | 137 | If you wish to have some symbols concealed for their Unicode equivalents, you may use these options. Each setting will conceal the following ASCII code block for an example output. 138 | 139 | ```purescript 140 | sum :: forall a f. Foldable f => Semiring a => f a -> a 141 | sum = foldl (\a b -> a + b) zero 142 | 143 | sumMod2 :: forall f. Foldable f => f Int -> Int 144 | sumMod2 xs = mod (sum xs) 2 145 | 146 | isSumEven :: forall f. Foldable => f Int -> Boolean 147 | isSumEven = (==) 0 <<< sumMod2 148 | ``` 149 | 150 | ### g:purescript_unicode_conceal_enable 151 | 152 | ```vim 153 | let g:purescript_unicode_conceal_enable = 1 154 | ``` 155 | 156 | Enables concealing. Conceals as: 157 | 158 | ```purescript 159 | sum ∷ ∀ a f. Foldable f ⇒ Semiring a ⇒ f a → a 160 | sum = foldl (λa b → a + b) zero 161 | 162 | sumMod2 ∷ ∀ f. Foldable f ⇒ f Int → Int 163 | sumMod2 xs = mod (sum xs) 2 164 | 165 | isSumEven ∷ ∀ f. Foldable ⇒ f Int → Boolean 166 | isSumEven = (≡) 0 ∘ sumMod2 167 | ``` 168 | 169 | ### g:purescript_unicode_conceal_disable_common 170 | 171 | ```vim 172 | let g:purescript_unicode_conceal_disable_common = 1 173 | ``` 174 | 175 | Disables concealing common symbols and just uses ones the compiler supports. Concealed as: 176 | 177 | ```purescript 178 | sum ∷ ∀ a f. Foldable f ⇒ Semiring a ⇒ f a → a 179 | sum = foldl (\a b → a + b) zero 180 | 181 | sumMod2 ∷ ∀ f. Foldable f ⇒ f Int → Int 182 | sumMod2 xs = mod (sum xs) 2 183 | 184 | isSumEven ∷ ∀ f. Foldable ⇒ f Int → Boolean 185 | isSumEven = (==) 0 <<< sumMod2 186 | ``` 187 | 188 | ### g:purescript_unicode_conceal_enable_discretionary 189 | 190 | ```vim 191 | let g:purescript_unicode_conceal_enable_discretionary = 1 192 | ``` 193 | 194 | Enables discretionary symbols concealing less common symbols that deviate further from the written code. Concealed as: 195 | 196 | ```purescript 197 | ∑ ∷ ∀ a f. Foldable f ⇒ Semiring a ⇒ f a → a 198 | ∑ = foldl (λa b → a + b) ∅ 199 | 200 | sumMod2 ∷ ∀ f. Foldable f ⇒ f ℤ → ℤ 201 | sumMod2 xs = mod (∑ xs) 2 202 | 203 | isSumEven ∷ ∀ f. Foldable ⇒ f ℤ → 𝔹 204 | isSumEven = (≡) 0 ∘ sumMod2 205 | ``` 206 | 207 | ## Developing 208 | 209 | Grab the suggested Git config by including with 210 | 211 | ```sh-session 212 | $ git config --local include.path ../.gitconfig 213 | ``` 214 | 215 | This includes [`.git-blame-ignore-revs`](https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt). 216 | 217 | Enter Nix dev shell ([enable Flakes](https://nixos.wiki/wiki/Flakes) if needed) 218 | 219 | ```sh-session 220 | $ nix develop 221 | ``` 222 | 223 | Or you can get an automatic shell via [`direnv`](https://direnv.net/) 224 | 225 | ```sh-session 226 | $ echo "use flake" > .envrc 227 | $ direnv allow 228 | ``` 229 | 230 | ## Contributing 231 | 232 | You can contribute to purescript-vim in several ways: 233 | 234 | 1. If you encounter a problem or have a question, please open an [issue](https://github.com/purescript-contrib/purescript-vim/issues) or post to the [mailing list](https://lists.sr.ht/~toastal/purescript-vim). We’ll do our best to work with you to resolve or answer it. 235 | 236 | 2. If you would like to contribute code, tests, or documentation, please read the [contributor guide](./CONTRIBUTING.md). It’s a short, helpful introduction to contributing to this library, including development instructions. 237 | 238 | 3. If you have written a library, tutorial, guide, or other resource based on this package, please share it on the [PureScript Discourse](https://discourse.purescript.org/)! Writing libraries and learning resources are a great way to help this library succ:eed. 239 | 240 | [PureScript]: http://www.purescript.org 241 | [Pathogen]: https://github.com/tpope/vim-pathogen 242 | [idris-vim]: https://github.com/idris-hackers/idris-vim 243 | [haskell-vim]: https://github.com/raichoo/haskell-vim 244 | [vim-plug]: https://github.com/junegunn/vim-plug 245 | [purescript-language-server]: https://github.com/nwolverson/purescript-language-server#vimcoc 246 | -------------------------------------------------------------------------------- /after/syntax/purescript.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | " Great for those that want Unicode, but their project’s config or style guide 3 | " does not endorse the usage. Much of the code is based on VimL code for 4 | " concealing Haskell, Idris, and OCaml. 5 | 6 | if !get(g:, 'purescript_unicode_conceal_enable', 0) || !has('conceal') || &encoding !=? 'utf-8' 7 | finish 8 | endif 9 | 10 | " vim: set fenc=utf-8: 11 | syntax match purescriptNiceOperator '->' conceal cchar=→ 12 | \ containedin=purescriptTypeExport,purescriptConstructorDecl,purescriptClassDecl,purescriptFunctionDecl,purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptOperatorType 13 | syntax match purescriptNiceOperator '<-' conceal cchar=← 14 | \ containedin=purescriptTypeExport,purescriptConstructorDecl,purescriptClassDecl,purescriptFunctionDecl,purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptOperatorType 15 | syntax match purescriptNiceOperator '=>' conceal cchar=⇒ 16 | \ containedin=purescriptTypeExport,purescriptConstructorDecl,purescriptClassDecl,purescriptFunctionDecl,purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptOperatorType 17 | syntax match purescriptNiceOperator "<=\ze[^<]" conceal cchar=⇐ 18 | \ containedin=purescriptTypeExport,purescriptConstructorDecl,purescriptClassDecl,purescriptFunctionDecl,purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptOperatorType 19 | syntax match purescriptNiceOperator '::' conceal cchar=∷ 20 | \ containedin=purescriptTypeExport,purescriptConstructorDecl,purescriptClassDecl,purescriptFunctionDecl,purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptOperatorType 21 | syntax keyword purescriptNiceOperator forall conceal cchar=∀ 22 | \ containedin=purescriptTypeExport,purescriptConstructorDecl,purescriptClassDecl,purescriptFunctionDecl,purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptOperatorType 23 | 24 | if !get(g:, 'purescript_unicode_conceal_disable_common', 1) 25 | syntax match purescriptNiceOperator "\/\@" conceal cchar=↝ 27 | \ containedin=purescriptTypeExport,purescriptConstructorDecl,purescriptClassDecl,purescriptFunctionDecl,purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptOperatorType 28 | syntax match purescriptNiceOperator '<<<' conceal cchar=∘ 29 | syntax match purescriptNiceOperator '==' conceal cchar=≡ 30 | syntax match purescriptNiceOperator '/=' conceal cchar=≠ 31 | " deals with Kliesli operator false positives 32 | syntax match purescriptNiceOperator "<=\ze[^<]" conceal cchar=≤ 33 | syntax match purescriptNiceOperator ">=\ze[^>]" conceal cchar=≥ 34 | endif 35 | 36 | " These have a general meaning in mathematics; nothing in this block should be 37 | " for ‘fun’ or ‘cute’. Perhaps that’s more suited for a new block or extension… 38 | if get(g:, 'purescript_unicode_conceal_enable_discretionary', 0) 39 | syntax keyword purescriptNiceOperator exists conceal cchar=∃ 40 | \ containedin=purescriptTypeExport,purescriptConstructorDecl,purescriptClassDecl,purescriptFunctionDecl,purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptOperatorType 41 | syntax match purescriptNiceOperator '\' conceal cchar=∑ 42 | syntax match purescriptNiceOperator '\' conceal cchar=∏ 43 | syntax match purescriptNiceOperator '\' conceal cchar=√ 44 | syntax match purescriptNiceOperator '\' conceal cchar=¬ 45 | syntax match purescriptNiceOperator "||\ze[[:alpha:][:space:]_([]" conceal cchar=∨ 46 | syntax match purescriptNiceOperator "&&\ze[[:alpha:][:space:]_([]" conceal cchar=∧ 47 | syntax match purescriptNiceOperator '`elem`' conceal cchar=∈ 48 | syntax match purescriptNiceOperator '`notElem`' conceal cchar=∉ 49 | syntax match purescriptNiceOperator '`union`' conceal cchar=∪ 50 | syntax match purescriptNiceOperator '`intersect`' conceal cchar=∩ 51 | syntax match purescriptNiceOperator '\' conceal cchar=∞ 52 | syntax match purescriptNiceIdentifier '\' conceal cchar=π 53 | syntax match purescriptNiceIdentifier '\' conceal cchar=τ 54 | syntax match purescriptNiceIdentifier '\' conceal cchar=∅ 55 | syntax match purescriptNiceIdentifier '\' conceal cchar=∅ 56 | syntax match purescriptNiceType '\' conceal cchar=𝔹 57 | \ containedin=purescriptType 58 | syntax match purescriptNiceType '\' conceal cchar=ℤ 59 | \ containedin=purescriptType 60 | syntax match purescriptNiceType '\' conceal cchar=ℕ 61 | \ containedin=purescriptType 62 | syntax match purescriptNiceType '\' conceal cchar=⊥ 63 | \ containedin=purescriptType 64 | " TODO: conceal primes with ′, ″, ‴, ⁗ 65 | endif 66 | 67 | highlight link purescriptNiceIdentifier Identifier 68 | highlight! link Conceal Identifier 69 | highlight link purescriptNiceType Type 70 | highlight! link Conceal Type 71 | highlight link purescriptNiceOperator Operator 72 | highlight! link Conceal Operator 73 | 74 | setlocal conceallevel=2 75 | -------------------------------------------------------------------------------- /doc/purescript-vim.txt: -------------------------------------------------------------------------------- 1 | *purescript-vim.txt* [PureScript][] language support for Vim and Neovim providing syntax highlighting and indentation based on based on [idris-vim][] and [haskell-vim][]. 2 | 3 | |purescript-intro| purescript-vim 4 | |purescript-License| License 5 | |purescript-Installation| Installation 6 | |purescript-Manual-Installation-no-plugin-manager| Manual Installation (no plugin manager) 7 | |purescript-Vim-8-packages| Vim 8 packages 8 | |purescript-Pathogen| Pathogen 9 | |purescript-vim-plug| vim-plug 10 | |purescript-Configuration| Configuration 11 | |purescript-Indentation| Indentation 12 | |purescript-g-purescript_disable_indent| g:purescript_disable_indent 13 | |purescript-g-purescript_indent_case| g:purescript_indent_case 14 | |purescript-g-purescript_indent_let| g:purescript_indent_let 15 | |purescript-g-purescript_indent_in| g:purescript_indent_in 16 | |purescript-g-purescript_indent_where| g:purescript_indent_where 17 | |purescript-g-purescript_indent_do| g:purescript_indent_do 18 | |purescript-g-purescript_indent_dot| g:purescript_indent_dot 19 | |purescript-Unicode-conceal| Unicode conceal 20 | |purescript-g-purescript_unicode_conceal_enable| g:purescript_unicode_conceal_enable 21 | |purescript-g-purescript_unicode_conceal_disable_common| g:purescript_unicode_conceal_disable_common 22 | |purescript-g-purescript_unicode_conceal_enable_discretionary| g:purescript_unicode_conceal_enable_discretionary 23 | |purescript-Developing| Developing 24 | |purescript-Contributing| Contributing 25 | 26 | PURESCRIPT-VIM *purescript-intro* 27 | 28 | [PureScript][] language support for Vim and Neovim providing syntax highlighting and indentation based on based on [idris-vim][] and [haskell-vim][]. 29 | 30 | See [purescript-language-server][] for details on how to set up language server support for [PureScript][]. 31 | 32 | 33 | LICENSE *purescript-License* 34 | 35 | This project is licensed under The 2-Clause BSD License ([BSD-2-Clause](https://opensource.org/licenses/BSD-2-Clause)) — see the LICENSE file in this project for details. 36 | 37 | 38 | INSTALLATION *purescript-Installation* 39 | 40 | 41 | MANUAL INSTALLATION (NO PLUGIN MANAGER) *purescript-Manual-Installation-no-plugin-manager* 42 | 43 | Copy content of this repository into your `~/.vim` directory (or `%HOME%\vimfiles` on Windows). 44 | 45 | Be sure that the following lines are in your `.vimrc` 46 | 47 | > 48 | syntax on 49 | filetype on 50 | filetype plugin indent on 51 | < 52 | 53 | 54 | VIM 8 PACKAGES *purescript-Vim-8-packages* 55 | 56 | If you have Vim version 8 (`vim --version | head -n1`), you can install plugins with the native pack system: 57 | 58 | > 59 | $ mkdir -p ~/.vim/pack/plugins/start/ 60 | $ cd ~/.vim/pack/plugins/start/ 61 | $ git clone https://github.com/purescript-contrib/purescript-vim.git 62 | < 63 | 64 | 65 | PATHOGEN *purescript-Pathogen* 66 | 67 | If you are using [Pathogen][], clone this repo into your `~/.vim/bundle` directory and you are ready to go. 68 | 69 | > 70 | $ cd ~/.vim/bundle 71 | $ git clone https://github.com/purescript-contrib/purescript-vim.git 72 | < 73 | 74 | 75 | VIM-PLUG *purescript-vim-plug* 76 | 77 | If you are using [vim-plug][], add the following line in between your `plug#begin` and `plug#end` calls for your Vim config file: 78 | 79 | > 80 | Plug 'purescript-contrib/purescript-vim' 81 | < 82 | 83 | Save and restart (Neo)Vim and run `:PlugInstall`. 84 | 85 | 86 | CONFIGURATION *purescript-Configuration* 87 | 88 | 89 | INDENTATION *purescript-Indentation* 90 | 91 | To configure indentation in `purescript-vim` you can use the following variables: 92 | 93 | 94 | G:PURESCRIPT_DISABLE_INDENT *purescript-g-purescript_disable_indent* 95 | 96 | Disable indentation altogether. 97 | 98 | > 99 | let g:purescript_disable_indent = 1 100 | < 101 | 102 | 103 | G:PURESCRIPT_INDENT_CASE *purescript-g-purescript_indent_case* 104 | 105 | > 106 | let g:purescript_indent_case = 5 107 | < 108 | 109 | > 110 | case xs of 111 | >>>>>[] -> ... 112 | >>>>>(y:ys) -> ... 113 | < 114 | 115 | 116 | G:PURESCRIPT_INDENT_LET *purescript-g-purescript_indent_let* 117 | 118 | > 119 | let g:purescript_indent_let = 4 120 | < 121 | 122 | > 123 | let x = 0 in 124 | >>>>x 125 | < 126 | 127 | 128 | G:PURESCRIPT_INDENT_IN *purescript-g-purescript_indent_in* 129 | 130 | > 131 | let g:purescript_indent_in = 1 132 | < 133 | 134 | > 135 | let x = 0 136 | >in x 137 | < 138 | 139 | 140 | G:PURESCRIPT_INDENT_WHERE *purescript-g-purescript_indent_where* 141 | 142 | > 143 | let g:purescript_indent_where = 6 144 | < 145 | 146 | > 147 | where f :: Int -> Int 148 | >>>>>>f x = x 149 | < 150 | 151 | 152 | G:PURESCRIPT_INDENT_DO *purescript-g-purescript_indent_do* 153 | 154 | > 155 | let g:purescript_indent_do = 3 156 | < 157 | 158 | > 159 | do x <- a 160 | >>>y <- b 161 | < 162 | 163 | 164 | G:PURESCRIPT_INDENT_DOT *purescript-g-purescript_indent_dot* 165 | 166 | > 167 | let g:purescript_indent_dot = 1 168 | < 169 | 170 | > 171 | unsnoc 172 | :: forall a 173 | >. List a 174 | -> Maybe (List a, a) 175 | < 176 | 177 | 178 | UNICODE CONCEAL *purescript-Unicode-conceal* 179 | 180 | If you wish to have some symbols concealed for their Unicode equivalents, you may use these options. Each setting will conceal the following ASCII code block for an example output. 181 | 182 | > 183 | sum :: forall a f. Foldable f => Semiring a => f a -> a 184 | sum = foldl (\a b -> a + b) zero 185 | 186 | sumMod2 :: forall f. Foldable f => f Int -> Int 187 | sumMod2 xs = mod (sum xs) 2 188 | 189 | isSumEven :: forall f. Foldable => f Int -> Boolean 190 | isSumEven = (==) 0 <<< sumMod2 191 | < 192 | 193 | 194 | G:PURESCRIPT_UNICODE_CONCEAL_ENABLE *purescript-g-purescript_unicode_conceal_enable* 195 | 196 | > 197 | let g:purescript_unicode_conceal_enable = 1 198 | < 199 | 200 | Enables concealing. Conceals as: 201 | 202 | > 203 | sum ∷ ∀ a f. Foldable f ⇒ Semiring a ⇒ f a → a 204 | sum = foldl (λa b → a + b) zero 205 | 206 | sumMod2 ∷ ∀ f. Foldable f ⇒ f Int → Int 207 | sumMod2 xs = mod (sum xs) 2 208 | 209 | isSumEven ∷ ∀ f. Foldable ⇒ f Int → Boolean 210 | isSumEven = (≡) 0 ∘ sumMod2 211 | < 212 | 213 | 214 | G:PURESCRIPT_UNICODE_CONCEAL_DISABLE_COMMON *purescript-g-purescript_unicode_conceal_disable_common* 215 | 216 | > 217 | let g:purescript_unicode_conceal_disable_common = 1 218 | < 219 | 220 | Disables concealing common symbols and just uses ones the compiler supports. Concealed as: 221 | 222 | > 223 | sum ∷ ∀ a f. Foldable f ⇒ Semiring a ⇒ f a → a 224 | sum = foldl (\a b → a + b) zero 225 | 226 | sumMod2 ∷ ∀ f. Foldable f ⇒ f Int → Int 227 | sumMod2 xs = mod (sum xs) 2 228 | 229 | isSumEven ∷ ∀ f. Foldable ⇒ f Int → Boolean 230 | isSumEven = (==) 0 <<< sumMod2 231 | < 232 | 233 | 234 | G:PURESCRIPT_UNICODE_CONCEAL_ENABLE_DISCRETIONARY *purescript-g-purescript_unicode_conceal_enable_discretionary* 235 | 236 | > 237 | let g:purescript_unicode_conceal_enable_discretionary = 1 238 | < 239 | 240 | Enables discretionary symbols concealing less common symbols that deviate further from the written code. Concealed as: 241 | 242 | > 243 | ∑ ∷ ∀ a f. Foldable f ⇒ Semiring a ⇒ f a → a 244 | ∑ = foldl (λa b → a + b) ∅ 245 | 246 | sumMod2 ∷ ∀ f. Foldable f ⇒ f ℤ → ℤ 247 | sumMod2 xs = mod (∑ xs) 2 248 | 249 | isSumEven ∷ ∀ f. Foldable ⇒ f ℤ → 𝔹 250 | isSumEven = (≡) 0 ∘ sumMod2 251 | < 252 | 253 | 254 | DEVELOPING *purescript-Developing* 255 | 256 | Grab the suggested Git config by including with 257 | 258 | > 259 | $ git config --local include.path ../.gitconfig 260 | < 261 | 262 | This includes [`.git-blame-ignore-revs`](https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt). 263 | 264 | Enter Nix dev shell ([enable Flakes](https://nixos.wiki/wiki/Flakes) if needed) 265 | 266 | > 267 | $ nix develop 268 | < 269 | 270 | Or you can get an automatic shell via [`direnv`](https://direnv.net/) 271 | 272 | > 273 | $ echo "use flake" > .envrc 274 | $ direnv allow 275 | < 276 | 277 | 278 | CONTRIBUTING *purescript-Contributing* 279 | 280 | You can contribute to purescript-vim in several ways: 281 | 282 | If you encounter a problem or have a question, please open an [issue](https://github.com/purescript-contrib/purescript-vim/issues) or post to the [mailing list](https://lists.sr.ht/~toastal/purescript-vim). We’ll do our best to work with you to resolve or answer it. 283 | 284 | If you would like to contribute code, tests, or documentation, please read the [contributor guide](./CONTRIBUTING.md). It’s a short, helpful introduction to contributing to this library, including development instructions. 285 | 286 | If you have written a library, tutorial, guide, or other resource based on this package, please share it on the [PureScript Discourse](https://discourse.purescript.org/)! Writing libraries and learning resources are a great way to help this library succ:eed. 287 | 288 | 289 | 290 | vim:tw=78:ts=8:ft=help:norl: 291 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1675431879, 6 | "narHash": "sha256-kF/24JC5syftRJE64GMK14/vdLRbuEzZjV1cqxBfCeU=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "959190ecf6e5b8c7c30721f3235de84d568359ee", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "NixOS", 14 | "ref": "nixpkgs-unstable", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs" 22 | } 23 | } 24 | }, 25 | "root": "root", 26 | "version": 7 27 | } 28 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "PureScript language support for Vim and Neovim"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 | }; 7 | 8 | outputs = 9 | { self 10 | , nixpkgs 11 | , ... 12 | }@inputs: 13 | let 14 | projectName = "purescript-vim"; 15 | 16 | supportedSystems = [ 17 | "x86_64-linux" 18 | "aarch64-linux" 19 | "x86_64-darwin" 20 | "aarch64-darwin" 21 | ]; 22 | 23 | forAllSystems = nixpkgs.lib.genAttrs supportedSystems; 24 | 25 | nixpkgsFor = forAllSystems (system: import nixpkgs { 26 | inherit system; 27 | overlays = [ self.overlays.default ]; 28 | }); 29 | in 30 | { 31 | overlays.default = final: prev: { }; 32 | 33 | apps = forAllSystems (system: 34 | let 35 | pkgs = nixpkgsFor.${system}; 36 | in 37 | { 38 | format = { 39 | type = "app"; 40 | program = pkgs.writeShellApplication 41 | { 42 | name = "format"; 43 | runtimeInputs = with pkgs; [ 44 | nixpkgs-fmt 45 | ]; 46 | text = '' 47 | set -euo pipefail 48 | cd ${self} 49 | nixpkgs-fmt . 50 | ''; 51 | } + "/bin/format"; 52 | }; 53 | }); 54 | 55 | checks = forAllSystems (system: 56 | let 57 | pkgs = nixpkgsFor.${system}; 58 | in 59 | { 60 | editorconfig = pkgs.runCommand "editorconfig-checker" 61 | { 62 | src = self; 63 | nativeBuildInputs = with pkgs; [ 64 | editorconfig-checker 65 | nixpkgs-fmt 66 | vim-vint 67 | ]; 68 | } '' 69 | set -euo pipefail 70 | cd ${self} 71 | editorconfig-checker | tee $out 72 | nixpkgs-fmt --check . | tee $out 73 | vint --style-problem **/*.vim | tee $out 74 | ''; 75 | }); 76 | 77 | devShells = forAllSystems (system: 78 | let 79 | pkgs = nixpkgsFor.${system}; 80 | in 81 | { 82 | default = pkgs.mkShell { 83 | name = projectName; 84 | buildInputs = with pkgs; [ 85 | editorconfig-checker 86 | nixpkgs-fmt 87 | nodejs # for npx in generate-doc.sh 88 | vim-vint 89 | ]; 90 | }; 91 | }); 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /ftdetect/purescript.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | augroup filetype_purescript 4 | autocmd! 5 | autocmd BufNewFile,BufRead *.purs setf purescript 6 | augroup END 7 | -------------------------------------------------------------------------------- /ftplugin/purescript.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | setlocal comments=s1fl:{-,mb:\ \ ,ex:-},:--\ \|,:-- 4 | setlocal commentstring=--\ %s 5 | setlocal include=^import 6 | setlocal includeexpr=printf('%s.purs',substitute(v:fname,'\\.','/','g')) 7 | 8 | let s:PS = [] 9 | fun! InitPureScript() 10 | let dirs = map( 11 | \ findfile('psc-package.json', expand('%:p:h') . ';/', -1), 12 | \ { idx, val -> fnamemodify(val, ':p:h') } 13 | \ ) 14 | if empty(dirs) 15 | let dirs = map( 16 | \ findfile('bower.json', expand('%:p:h') . ';/', -1), 17 | \ { idx, val -> fnamemodify(val, ':p:h') } 18 | \ ) 19 | if empty(dirs) 20 | return 21 | endif 22 | endif 23 | 24 | let path = expand('%:p') 25 | for p in s:PS 26 | if stridx(path, p[0], 0) == 0 27 | let &l:path=p[1] 28 | return 29 | endif 30 | endfor 31 | 32 | let dir = dirs[len(dirs) - 1] 33 | let gp = globpath(dir, 'src/**/*.purs', v:true, v:true) 34 | if empty(gp) 35 | return 36 | endif 37 | 38 | let &l:path=join([dir, dir . '/bower_components/**', dir . '/src/**'], ',') 39 | call add(s:PS, [dir, &l:path]) 40 | endfun 41 | call InitPureScript() 42 | -------------------------------------------------------------------------------- /generate-doc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | npx github:mklabs/vim-markdown-helpfile < README.md > doc/purescript-vim.txt 3 | -------------------------------------------------------------------------------- /indent/purescript.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | " indentation for purescript 3 | " 4 | " Based on idris indentation 5 | " 6 | " author: raichoo (raichoo@googlemail.com) 7 | " 8 | 9 | if exists('g:purescript_disable_indent') 10 | finish 11 | endif 12 | 13 | if !exists('g:purescript_indent_case') 14 | " case xs of 15 | " >>>>>[] -> ... 16 | " >>>>>(y:ys) -> ... 17 | let g:purescript_indent_case = 4 18 | endif 19 | 20 | if !exists('g:purescript_indent_let') 21 | " let x = 0 in 22 | " >>>>x 23 | let g:purescript_indent_let = 4 24 | endif 25 | 26 | if !exists('g:purescript_indent_in') 27 | " let x = 0 28 | " >in 29 | let g:purescript_indent_in = 1 30 | endif 31 | 32 | if !exists('g:purescript_indent_where') 33 | " where 34 | " >>f :: Int -> Int 35 | " >>f x = x 36 | let g:purescript_indent_where = 2 37 | endif 38 | 39 | if !exists('g:purescript_indent_do') 40 | " do x <- a 41 | " >>>y <- b 42 | let g:purescript_indent_do = 3 43 | endif 44 | 45 | if !exists('g:purescript_indent_dot') 46 | " f 47 | " :: forall a 48 | " >. String 49 | " -> String 50 | let g:purescript_indent_dot = 1 51 | endif 52 | 53 | setlocal indentexpr=GetPurescriptIndent() 54 | setlocal indentkeys=!^F,o,O,},=where,=in,=::,=∷,=->,=→,==>,=⇒ 55 | 56 | function! s:GetSynStack(lnum, col) 57 | return map(synstack(a:lnum, a:col), { key, val -> synIDattr(val, 'name') }) 58 | endfunction 59 | 60 | function! GetPurescriptIndent() 61 | let ppline = getline(v:lnum - 2) 62 | let prevline = getline(v:lnum - 1) 63 | let line = getline(v:lnum) 64 | 65 | if line =~# '^\s*\' 66 | let s = indent(v:lnum - 1) 67 | return max([s, &l:shiftwidth]) 68 | endif 69 | 70 | if line =~# '^\s*\' 71 | let n = v:lnum 72 | let s = 0 73 | 74 | while s <= 0 && n > 0 75 | let n = n - 1 76 | let s = match(getline(n), '\') 77 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') !=? -1 78 | let s = -1 79 | endif 80 | endwhile 81 | 82 | return s + g:purescript_indent_in 83 | endif 84 | 85 | let s = match(prevline, '^\s*\zs\(--\|import\)') 86 | if s >= 0 87 | " comments 88 | " imports 89 | return s 90 | endif 91 | 92 | if prevline =~# '^\S.*\(::\|∷\)' && line !~# '^\s*\(\.\|->\|→\|=>\|⇒\)' && prevline !~# '^instance' 93 | " f :: String 94 | " -> String 95 | return 0 96 | endif 97 | 98 | let s = match(prevline, '[[:alnum:][:blank:]]\@<=|[[:alnum:][:blank:]$]') 99 | if s >= 0 && prevline !~# '^class\>' && index(s:GetSynStack(v:lnum - 1, s), 'purescriptFunctionDecl') == -1 100 | " ident pattern guards but not if we are in a type declaration 101 | " what we detect using syntax groups 102 | if prevline =~# '|\s*otherwise\>' 103 | return indent(search('^\s*\k', 'bnW')) 104 | " somehow this pattern does not work :/ 105 | " return indent(search('^\(\s*|\)\@!', 'bnW')) 106 | else 107 | return s 108 | endif 109 | endif 110 | 111 | let s = match(line, '\%(\\.\{-}\)\@<=\(->\|→\)') 112 | if s >= 0 113 | " inline lambda 114 | return indent(v:lnum) 115 | endif 116 | 117 | " indent rules for -> (lambdas and case expressions) 118 | let s = match(line, '\(->\|→\)') 119 | let p = match(prevline, '\\') 120 | " protect that we are not in a type signature 121 | " and not in a case expression 122 | if s >= 0 && index(s:GetSynStack(s == 0 ? v:lnum - 1 : v:lnum, max([1, s])), 'purescriptFunctionDecl') == -1 123 | \ && p >= 0 && index(s:GetSynStack(v:lnum - 1, p), 'purescriptString') == -1 124 | return p 125 | endif 126 | 127 | if prevline =~# '^\S' 128 | " start typing signature, function body, data & newtype on next line 129 | return &l:shiftwidth 130 | endif 131 | 132 | if ppline =~# '^\S' && prevline =~# '^\s*$' 133 | return 0 134 | endif 135 | 136 | if line =~# '^\s*\%(::\|∷\)' 137 | return match(prevline, '\S') + &l:shiftwidth 138 | endif 139 | 140 | if prevline =~# '^\s*\(::\|∷\)\s*\(forall\|∀\)' 141 | return match(prevline, '\S') + g:purescript_indent_dot 142 | endif 143 | 144 | let s = match(prevline, '^\s*\zs\%(::\|∷\|=>\|⇒\|->\|→\)') 145 | let r = match(prevline, '^\s*\zs\.') 146 | if s >= 0 || r >= 0 147 | if s >= 0 148 | if line !~# '^\s*\%(::\|∷\|=>\|⇒\|->\|→\)' && line !~# '^\s*$' 149 | return s - 2 150 | else 151 | return s 152 | endif 153 | elseif r >= 0 154 | if line !~# '^\s\%(::\|∷\|=>\|⇒\|->\|→\)' 155 | return r - g:purescript_indent_dot 156 | else 157 | return r 158 | endif 159 | endif 160 | endif 161 | 162 | if prevline =~# '[!#$%&*+./<>?@\\^~-]\s*$' 163 | let s = match(prevline, '=') 164 | if s > 0 165 | return s + &l:shiftwidth 166 | endif 167 | 168 | let s = match(prevline, '\<:\>') 169 | if s > 0 170 | return s + &l:shiftwidth 171 | else 172 | return match(prevline, '\S') + &l:shiftwidth 173 | endif 174 | endif 175 | 176 | if prevline =~# '[{([][^})\]]\+$' 177 | echom 'return 1' 178 | return match(prevline, '[{([]') 179 | endif 180 | 181 | let s = match(prevline, '\\s\+\zs\S') 182 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 183 | return s 184 | endif 185 | 186 | let s = match(prevline, '\\s*$') 187 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 188 | return s + g:purescript_indent_let 189 | endif 190 | 191 | let s = match(prevline, '\\s\+.\+\(\\)\?\s*$') 192 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 193 | return match(prevline, '\') + g:purescript_indent_let 194 | endif 195 | 196 | let s = searchpairpos('\%(--.\{-}\)\@', '\', '\.*\zs$', 'bnrc')[0] 197 | if s > 0 198 | " this rule ensures that using `=` in visual mode will correctly indent 199 | " `if then else`, but it does not handle lines after `then` and `else` 200 | if line =~# '\<\%(then\|else\)\>' 201 | return match(getline(s), '\') + &l:shiftwidth 202 | endif 203 | endif 204 | 205 | let p = match(prevline, '\\%(.\{-}\.\{-}\\)\@!') 206 | if p > 0 207 | return p + &l:shiftwidth 208 | endif 209 | 210 | let s = match(prevline, '=\s*$') 211 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 212 | return match(prevline, '\S') + &l:shiftwidth 213 | endif 214 | 215 | let s = match(prevline, '[{([]\s*$') 216 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 217 | return match(prevline, '\S') + (line !~# '^\s*[})]]' ? 0 : &l:shiftwidth) 218 | endif 219 | 220 | if prevline =~# '^class' 221 | return &l:shiftwidth 222 | endif 223 | 224 | let s = match(prevline, '\\s*$') 225 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 226 | return match(prevline, '\S') + g:purescript_indent_where 227 | endif 228 | 229 | let s = match(prevline, '\\s\+\zs\S\+.*$') 230 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 231 | return s 232 | endif 233 | 234 | let s = match(prevline, '\\s*$') 235 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 236 | return match(prevline, '\S') + g:purescript_indent_do 237 | endif 238 | 239 | let s = match(prevline, '\\s\+\zs\S\+.*$') 240 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 241 | return s 242 | endif 243 | 244 | let s = match(prevline, '^\s*\\s\+[^=]\+\s\+=\s\+\S\+.*$') 245 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 246 | return match(prevline, '=') 247 | endif 248 | 249 | let s = match(prevline, '\\s\+.\+\\s*$') 250 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 251 | return match(prevline, '\') + g:purescript_indent_case 252 | endif 253 | 254 | if prevline =~# '^\s*\<\data\>\s\+\S\+\s*$' 255 | return match(prevline, '\') + &l:shiftwidth 256 | endif 257 | 258 | let s = match(prevline, '^\s*[}\]]') 259 | if s >= 0 && index(s:GetSynStack(v:lnum - 1, s), 'purescriptString') == -1 260 | return match(prevline, '\S') - &l:shiftwidth 261 | endif 262 | 263 | return match(prevline, '\S') 264 | endfunction 265 | -------------------------------------------------------------------------------- /syntax/purescript.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | " syntax highlighting for purescript 3 | " 4 | " Heavily modified version of the purescript syntax 5 | " highlighter to support purescript. 6 | " 7 | " author: raichoo (raichoo@googlemail.com) 8 | 9 | if exists('b:current_syntax') 10 | finish 11 | endif 12 | 13 | " Values 14 | syn match purescriptIdentifier "\<[_[:lower:]]\(\w\|\'\)*\>" 15 | syn match purescriptNumber "0[xX][0-9a-fA-F]\+\|0[oO][0-7]\|[0-9]\+" 16 | syn match purescriptFloat "[0-9]\+\.[0-9]\+\([eE][-+]\=[0-9]\+\)\=" 17 | syn keyword purescriptBoolean true false 18 | 19 | " Delimiters 20 | syn match purescriptDelimiter "[,;|.()[\]{}]" 21 | 22 | " Type 23 | syn match purescriptType "\%(\" contained 24 | \ containedin=purescriptTypeAlias 25 | \ nextgroup=purescriptType,purescriptTypeVar skipwhite 26 | syn match purescriptTypeVar "\<[_[:lower:]]\(\w\|\'\)*\>" contained 27 | \ containedin=purescriptData,purescriptNewtype,purescriptTypeAlias,purescriptFunctionDecl 28 | syn region purescriptTypeExport matchgroup=purescriptType start="\<[[:upper:]]\(\S\&[^,.]\)*\>("rs=e-1 matchgroup=purescriptDelimiter end=")" contained extend 29 | \ contains=purescriptConstructor,purescriptDelimiter 30 | 31 | " Constructor 32 | syn match purescriptConstructor "\%(\" 33 | syn region purescriptConstructorDecl matchgroup=purescriptConstructor start="\<[[:upper:]]\w*\>" end="\(|\|$\)"me=e-1,re=e-1 contained 34 | \ containedin=purescriptData,purescriptNewtype 35 | \ contains=purescriptType,purescriptTypeVar,purescriptDelimiter,purescriptOperatorType,purescriptOperatorTypeSig,@purescriptComment 36 | 37 | 38 | " Function 39 | syn match purescriptFunction "\%(\" contained 40 | " syn match purescriptFunction "\<[_[:lower:]]\(\w\|\'\)*\>" contained 41 | syn match purescriptFunction "(\%(\" containedin=purescriptClassDecl contained 50 | \ nextgroup=purescriptClassName 51 | \ skipnl 52 | syn match purescriptClassName "\<[[:upper:]]\w*\>" containedin=purescriptClassDecl contained 53 | 54 | " Module 55 | syn match purescriptModuleName "\(\u\w\*\.\?\)*" contained excludenl 56 | syn match purescriptModuleKeyword "\" 57 | syn match purescriptModule "^module\>\s\+\<\(\w\+\.\?\)*\>" 58 | \ contains=purescriptModuleKeyword,purescriptModuleName 59 | \ nextgroup=purescriptModuleParams 60 | \ skipwhite 61 | \ skipnl 62 | \ skipempty 63 | syn region purescriptModuleParams start="(" skip="([^)]\{-})" end=")" fold contained keepend 64 | \ contains=purescriptClassDecl,purescriptClass,purescriptClassName,purescriptDelimiter,purescriptType,purescriptTypeExport,purescriptStructure,purescriptModuleKeyword,@purescriptComment 65 | \ nextgroup=purescriptImportParams skipwhite 66 | 67 | " Import 68 | syn match purescriptImportKeyword "\<\(foreign\|import\|qualified\)\>" 69 | syn match purescriptImport "\\s\+\(qualified\s\+\)\?\<\(\w\+\.\?\)*" 70 | \ contains=purescriptImportKeyword,purescriptModuleName 71 | \ nextgroup=purescriptImportParams,purescriptImportAs,purescriptImportHiding 72 | \ skipwhite 73 | syn region purescriptImportParams 74 | \ start="(" 75 | \ skip="([^)]\{-})" 76 | \ end=")" 77 | \ contained 78 | \ contains=purescriptClass,purescriptClass,purescriptStructure,purescriptType,purescriptIdentifier 79 | \ nextgroup=purescriptImportAs 80 | \ skipwhite 81 | syn keyword purescriptAsKeyword as contained 82 | syn match purescriptImportAs "\\_s\+\u\w*" 83 | \ contains=purescriptAsKeyword,purescriptModuleName 84 | \ nextgroup=purescriptModuleName 85 | syn keyword purescriptHidingKeyword hiding contained 86 | syn match purescriptImportHiding "hiding" 87 | \ contained 88 | \ contains=purescriptHidingKeyword 89 | \ nextgroup=purescriptImportParams 90 | \ skipwhite 91 | syn region purescriptFoldImports start="import" end=/import.*\n^$/ fold transparent keepend 92 | 93 | " Function declaration 94 | syn region purescriptFunctionDecl 95 | \ excludenl start="^\z(\s*\)\(\(foreign\s\+import\)\_s\+\)\?[_[:lower:]]\(\w\|\'\)*\_s\{-}\(::\|∷\)" 96 | \ end="^\z1\=\S"me=s-1,re=s-1 keepend 97 | \ contains=purescriptFunctionDeclStart,purescriptForall,purescriptOperatorType,purescriptOperatorTypeSig,purescriptType,purescriptTypeVar,purescriptDelimiter,@purescriptComment 98 | syn region purescriptFunctionDecl 99 | \ excludenl start="^\z(\s*\)where\z(\s\+\)[_[:lower:]]\(\w\|\'\)*\_s\{-}\(::\|∷\)" 100 | \ end="^\(\z1\s\{5}\z2\)\=\S"me=s-1,re=s-1 keepend 101 | \ contains=purescriptFunctionDeclStart,purescriptForall,purescriptOperatorType,purescriptOperatorTypeSig,purescriptType,purescriptTypeVar,purescriptDelimiter,@purescriptComment 102 | syn region purescriptFunctionDecl 103 | \ excludenl start="^\z(\s*\)let\z(\s\+\)[_[:lower:]]\(\w\|\'\)*\_s\{-}\(::\|∷\)" 104 | \ end="^\(\z1\s\{3}\z2\)\=\S"me=s-1,re=s-1 keepend 105 | \ contains=purescriptFunctionDeclStart,purescriptForall,purescriptOperatorType,purescriptOperatorTypeSig,purescriptType,purescriptTypeVar,purescriptDelimiter,@purescriptComment 106 | syn match purescriptFunctionDeclStart "^\s*\(\(foreign\s\+import\|let\|where\)\_s\+\)\?\([_[:lower:]]\(\w\|\'\)*\)\_s\{-}\(::\|∷\)" contained 107 | \ contains=purescriptImportKeyword,purescriptWhere,purescriptLet,purescriptFunction,purescriptOperatorType 108 | syn keyword purescriptForall forall 109 | syn match purescriptForall "∀" 110 | 111 | " Keywords 112 | syn keyword purescriptConditional if then else 113 | syn keyword purescriptStatement do case of in ado 114 | syn keyword purescriptLet let 115 | syn keyword purescriptWhere where 116 | syn match purescriptStructure "\<\(data\|newtype\|type\|kind\)\>" 117 | \ nextgroup=purescriptType skipwhite 118 | syn keyword purescriptStructure derive 119 | syn keyword purescriptStructure instance 120 | \ nextgroup=purescriptFunction skipwhite 121 | 122 | " Infix 123 | syn match purescriptInfixKeyword "\<\(infix\|infixl\|infixr\)\>" 124 | syn match purescriptInfix "^\(infix\|infixl\|infixr\)\>\s\+\([0-9]\+\)\s\+\(type\s\+\)\?\(\S\+\)\s\+as\>" 125 | \ contains=purescriptInfixKeyword,purescriptNumber,purescriptAsKeyword,purescriptConstructor,purescriptStructure,purescriptFunction,purescriptBlockComment 126 | \ nextgroup=purescriptFunction,purescriptOperator,@purescriptComment 127 | 128 | " Operators 129 | syn match purescriptOperator "\([-!#$%&\*\+/<=>\?@\\^|~:]\|\<_\>\)" 130 | syn match purescriptOperatorType "\%(\.*\)\@40\|<-\|[\\→←]\)" 133 | syn match purescriptOperatorTypeSig "\(->\|<-\|=>\|<=\|\~>\|::\|[∷∀→←⇒⇐↝]\)" contained 134 | \ nextgroup=purescriptType skipwhite skipnl skipempty 135 | 136 | " Type definition 137 | syn region purescriptData start="^data\s\+\([[:upper:]]\w*\)" end="^\S"me=s-1,re=s-1 transparent 138 | syn match purescriptDataStart "^data\s\+\([[:upper:]]\w*\)" contained 139 | \ containedin=purescriptData 140 | \ contains=purescriptStructure,purescriptType,purescriptTypeVar 141 | syn match purescriptForeignData "\" 142 | \ contains=purescriptImportKeyword,purescriptStructure 143 | \ nextgroup=purescriptType skipwhite 144 | 145 | syn region purescriptNewtype start="^newtype\s\+\([[:upper:]]\w*\)" end="^\S"me=s-1,re=s-1 transparent 146 | syn match purescriptNewtypeStart "^newtype\s\+\([[:upper:]]\w*\)" contained 147 | \ containedin=purescriptNewtype 148 | \ contains=purescriptStructure,purescriptType,purescriptTypeVar 149 | 150 | syn region purescriptTypeAlias start="^type\s\+\([[:upper:]]\w*\)" end="^\S"me=s-1,re=s-1 transparent 151 | syn match purescriptTypeAliasStart "^type\s\+\([[:upper:]]\w*\)" contained 152 | \ containedin=purescriptTypeAlias 153 | \ contains=purescriptStructure,purescriptType,purescriptTypeVar 154 | 155 | " String 156 | syn match purescriptChar "'[^'\\]'\|'\\.'\|'\\u[0-9a-fA-F]\{4}'" 157 | syn region purescriptString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell 158 | syn region purescriptMultilineString start=+'"'+ end=+'"'+ fold contains=@Spell 159 | 160 | " Comment 161 | syn match purescriptLineComment "---*\([^-!#$%&\*\+./<=>\?@\\^|~].*\)\?$" contains=purescriptCommentTodo,@Spell 162 | syn region purescriptBlockComment start="{-" end="-}" fold 163 | \ contains=purescriptBlockComment,@Spell 164 | syn cluster purescriptComment contains=purescriptLineComment,purescriptBlockComment,@Spell 165 | syn keyword purescriptCommentTodo 166 | \ contained TODO FIXME XXX DEBUG BROKEN REFACTOR REFACT RFCTR SMELL NEEDSWORK TBD TOBEDONE BUG BUGFIX RFE WTF HACK CLEVER MAGIC 167 | 168 | syn sync minlines=50 169 | 170 | " highlight links 171 | highlight def link purescriptModule Include 172 | highlight def link purescriptImport Include 173 | highlight def link purescriptModuleKeyword purescriptKeyword 174 | highlight def link purescriptImportAs Include 175 | highlight def link purescriptModuleName Include 176 | highlight def link purescriptModuleParams purescriptDelimiter 177 | highlight def link purescriptImportKeyword purescriptKeyword 178 | highlight def link purescriptAsKeyword purescriptKeyword 179 | highlight def link purescriptHidingKeyword purescriptKeyword 180 | 181 | highlight def link purescriptConditional Conditional 182 | highlight def link purescriptWhere purescriptKeyword 183 | highlight def link purescriptInfixKeyword purescriptKeyword 184 | 185 | highlight def link purescriptBoolean Boolean 186 | highlight def link purescriptNumber Number 187 | highlight def link purescriptFloat Float 188 | 189 | highlight def link purescriptDelimiter Delimiter 190 | 191 | highlight def link purescriptOperatorTypeSig purescriptOperatorType 192 | highlight def link purescriptOperatorFunction purescriptOperatorType 193 | highlight def link purescriptOperatorType purescriptOperator 194 | 195 | highlight def link purescriptConstructorDecl purescriptConstructor 196 | highlight def link purescriptConstructor purescriptFunction 197 | 198 | highlight def link purescriptTypeVar Identifier 199 | highlight def link purescriptForall purescriptStatement 200 | 201 | highlight def link purescriptChar String 202 | highlight def link purescriptBacktick purescriptOperator 203 | highlight def link purescriptString String 204 | highlight def link purescriptMultilineString String 205 | 206 | highlight def link purescriptLineComment purescriptComment 207 | highlight def link purescriptBlockComment purescriptComment 208 | 209 | " purescript general highlights 210 | highlight def link purescriptClass purescriptKeyword 211 | highlight def link purescriptClassName Type 212 | highlight def link purescriptStructure purescriptKeyword 213 | highlight def link purescriptKeyword Keyword 214 | highlight def link purescriptStatement Statement 215 | highlight def link purescriptLet Statement 216 | highlight def link purescriptOperator Operator 217 | highlight def link purescriptFunction Function 218 | highlight def link purescriptType Type 219 | highlight def link purescriptComment Comment 220 | 221 | let b:current_syntax = 'purescript' 222 | --------------------------------------------------------------------------------