Vim support for Factor
======================
-This directory contains various support files that make editing Factor code
-more pleasant in Vim.
+This directory contains various support files that make editing
+Factor code more pleasant in Vim.
## Installation
-The file-layout exactly matches the Vim runtime structure,
-so you can install them by copying the contents of this directory
-into `~/.vim/` or the equivalent path on other platforms
-(open Vim and type `:help 'runtimepath'` for details).
+The file-layout exactly matches the Vim runtime structure, so
+you can install them by copying the contents of this directory
+into `~/.vim/` or the equivalent path on other platforms (open
+Vim and type `:help 'runtimepath'` for details).
## File organization
The current set of files is as follows:
-* ftdetect/factor.vim - Teach Vim when to load Factor support files.
-* ftplugin/factor.vim - Teach Vim to follow the Factor Coding Style guidelines.
-* ftplugin/factor-docs.vim - Teach Vim about documentation style differences.
-* plugin/factor.vim - Teach Vim some commands for navigating Factor source code. See below.
-* syntax/factor.vim - Teach Vim about highlighting Factor source code syntax.
- * syntax/factor/generated.vim - Syntax highlighting lessons generated from a Factor VM.
-* indent/factor.vim - Teach Vim to automatically indent Factor source code.
+* ftdetect/factor.vim - Teach Vim when to load Factor support
+ files.
+* ftplugin/factor.vim - Teach Vim to follow the Factor Coding
+ Style guidelines. Contains an optional autopairs plugin for
+ Factor. See configuration below.
+* ftplugin/factor-docs.vim - Teach Vim about documentation style
+ differences.
+* plugin/factor.vim - Teach Vim some commands for navigating
+ Factor source code. See configuration below.
+* syntax/factor.vim - Teach Vim about highlighting Factor source
+ code syntax.
+ * syntax/factor/generated.vim - Syntax highlighting lessons
+ generated from a Factor VM.
+* indent/factor.vim - Teach Vim to automatically indent Factor
+ source code.
## Commands
-The `plugin/factor.vim` file implements the following commands for navigating Factor source.
+The `plugin/factor.vim` file implements the following commands
+for navigating Factor source.
### :FactorVocab factor.vocab.name
-Opens the source file implementing the `factor.vocab.name` vocabulary.
+Opens the source file implementing the `factor.vocab.name`
+vocabulary.
### :NewFactorVocab factor.vocab.name
-Creates a new factor vocabulary under the working vocabulary root.
+Creates a new factor vocabulary under the working vocabulary
+root.
### :FactorVocabImpl
Opens the main implementation file for the current vocabulary
-(name.factor). The keyboard shortcut `<Leader>fi` is bound to this command.
+(name.factor). The keyboard shortcut `<Leader>fi` is bound to
+this command.
### :FactorVocabDocs
Opens the documentation file for the current vocabulary
-(name-docs.factor). The keyboard shortcut `<Leader>fd` is bound to this command.
+(name-docs.factor). The keyboard shortcut `<Leader>fd` is bound
+to this command.
### :FactorVocabTests
Opens the unit test file for the current vocabulary
-(name-tests.factor). The keyboard shortcut `<Leader>ft` is bound to this command.
+(name-tests.factor). The keyboard shortcut `<Leader>ft` is bound
+to this command.
## Configuration
-In order for the `:FactorVocab` command to work, you'll need to set some variables in your vimrc file.
+In order for the `:FactorVocab` command to work, you'll need to
+set some variables in your vimrc file.
### g:FactorRoot
### g:FactorVocabRoots
-This variable should be set to a list of Factor vocabulary roots.
-The paths may be either relative to g:FactorRoot or absolute paths.
-The default value is `["core", "basis", "extra", "work"]`.
+This variable should be set to a list of Factor vocabulary
+roots. The paths may be either relative to g:FactorRoot or
+absolute paths. The default value is `["core", "basis", "extra",
+"work"]`.
### g:FactorNewVocabRoot
This variable should be set to the vocabulary root in which
-vocabularies created with NewFactorVocab should be created.
-The default value is `work`.
+vocabularies created with NewFactorVocab should be created. The
+default value is `work`.
+
+### g:EnableFactorAutopairs
+
+This variable should be set to 1 if you want to enable the
+autopairs functionality.
## Note
-The `syntax/factor/generated.vim` syntax highlighting file
-is automatically generated to include the names of all the
+The `syntax/factor/generated.vim` syntax highlighting file is
+automatically generated to include the names of all the
vocabularies Factor knows about.
-To regenerate it manually, run the following code in the listener:
+To regenerate it manually, run the following code in the
+listener:
"editors.vim.generate-syntax" run
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
- finish
+ finish
endif
let b:did_ftplugin = 1
" Code formatting settings loosely adapted from:
" http://concatenative.org/wiki/view/Factor/Coding%20Style
-" Tabs are not allowed in Factor source files; use four spaces instead.
+" Tabs are not allowed in Factor source files; use four spaces
+" instead.
setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4
" Try to limit lines to 64 characters.
-setlocal textwidth=64
-augroup factorTextWidth
- au!
- au BufEnter <buffer> 2match Error /\%>64v.\+/
- au BufLeave <buffer> 2match none
-augroup END
+setlocal textwidth=64 colorcolumn=+1
+hi ColorColumn ctermbg=darkgrey guibg=#1e2528
" Teach Vim what comments look like.
setlocal comments+=b:!,b:#!
-" Make all of these characters part of a word (useful for skipping
-" over words with w, e, and b)
+" Make all of these characters part of a word (useful for
+" skipping over words with w, e, and b)
setlocal iskeyword=33-126,128-255
+
+" Insert closing brackets and quotes, spaces, stack effects ...
+" examples ("|" is the position of the cursor):
+" |if + [ → [|] if
+" [|] + <Space> → [ | ]
+" [|] + <CR> → [
+" |
+" ]
+" (|) + <Space> → ( |-- )
+" [|] + = → [=|=]
+" [|] + <BS> → |
+if exists("g:EnableFactorAutopairs") &&
+ \g:EnableFactorAutopairs == 1
+
+ function s:RemoveTrailingSpaces()
+ let save_view = winsaveview()
+ %s/ \+$//e
+ call winrestview(save_view)
+ endfunction
+
+ au BufWrite <buffer> :call s:RemoveTrailingSpaces()
+
+ function s:Insert(before, after)
+ return a:before .. a:after ..
+ \repeat("\<C-G>U\<Left>", strlen(a:after))
+ endfunction
+
+ function s:PadAfter()
+ return getline('.')[col('.') - 1] != ' ' ?
+ \s:Insert('', ' ') : ''
+ endfunction
+
+ function s:Context()
+ return strpart(getline('.'), col('.') - 2, 2)
+ endfunction
+
+ function s:WiderContext()
+ return strpart(getline('.'), col('.') - 3, 4)
+ endfunction
+
+ function s:OpenParenthesis()
+ return (s:Context() != '()' ? s:PadAfter() : '') ..
+ \s:Insert('(', ')')
+ endfunction
+
+ function s:OpenBracket()
+ let context = s:Context()
+ return (
+ \context != '==' && context != '[]' ? s:PadAfter() : ''
+ \) .. s:Insert('[', ']')
+ endfunction
+
+ function s:OpenBrace()
+ return s:PadAfter() .. s:Insert('{', '}')
+ endfunction
+
+ function s:Equal()
+ let context = s:Context()
+ if context == '[]' || context == '=='
+ return s:Insert('=', '=')
+ else
+ return s:Insert('=', '')
+ endif
+ endfunction
+
+ function s:Quote()
+ return s:Context() == '""' ? '' :
+ \(s:PadAfter() .. s:Insert('"', '"'))
+ endfunction
+
+ function s:Return()
+ let context = s:Context()
+ let widercontext = s:WiderContext()
+ if context == '[]' || context == '{}' ||
+ \widercontext == '[ ]' || widercontext == '{ }'
+ return "\<CR>\<C-O>O"
+ else
+ return "\<CR>"
+ endif
+ endfunction
+
+ function s:Backspace()
+ let context = s:Context()
+ let widercontext = s:WiderContext()
+ if widercontext == '[ ]' || widercontext == '( )' ||
+ \widercontext == '{ }' || context == '""' ||
+ \context == '==' || context == '()' ||
+ \context == '[]' || context == '{}'
+ return "\<Del>\<BS>"
+ else
+ return "\<BS>"
+ endif
+ endfunction
+
+ function s:Space()
+ let context = s:Context()
+ if context == '[]' || context == '{}' ||
+ \s:WiderContext() == '(())' ||
+ \strpart(getline('.'), col('.') - 5, 5) == ':> ()'
+ return s:Insert(' ', ' ')
+ elseif context == '()'
+ return s:Insert(' ', '-- ')
+ else
+ return s:Insert(' ', '')
+ endif
+ endfunction
+
+ inoremap <buffer> <expr> ( <SID>OpenParenthesis()
+ inoremap <buffer> <expr> [ <SID>OpenBracket()
+ inoremap <buffer> <expr> { <SID>OpenBrace()
+ inoremap <buffer> <expr> = <SID>Equal()
+ inoremap <buffer> <expr> " <SID>Quote()
+ inoremap <buffer> <expr> <CR> <SID>Return()
+ inoremap <buffer> <expr> <BS> <SID>Backspace()
+ inoremap <buffer> <expr> <Space> <SID>Space()
+
+endif
+
+" vim:sw=2:et: