diff --git a/vim/vim.symlink/UltiSnips/javascript.snippets b/vim/vim.symlink/UltiSnips/javascript.snippets
new file mode 100644
index 0000000..e69de29
diff --git a/vim/vim.symlink/UltiSnips/javascript_mocha.snippets b/vim/vim.symlink/UltiSnips/javascript_mocha.snippets
new file mode 100644
index 0000000..9a335c1
--- /dev/null
+++ b/vim/vim.symlink/UltiSnips/javascript_mocha.snippets
@@ -0,0 +1,37 @@
+snippet ttest
+/* eslint-env node, mocha */
+/* eslint-disable no-unused-expressions */
+
+import chai from 'chai';
+
+import sinon from 'sinon';
+
+import sinonChai from 'sinon-chai';
+chai.use(sinonChai);
+
+const expect = chai.expect;
+
+$0
+endsnippet
+
+snippet tdescribe
+describe('${1:Description}', () => {
+ ${2:// specs}
+});$0
+endsnippet
+
+snippet tbefore
+beforeEach(() => {
+ ${1:// do stuff}
+});$0
+endsnippet
+
+snippet tit
+it('should ${1:do something exciting}', () => {
+ ${2:// spec}
+});$0
+endsnippet
+
+snippet texpect
+expect(${1:value}).to.${2:be.true};$0
+endsnippet
diff --git a/vim/vim.symlink/UltiSnips/javascript_module.snippets b/vim/vim.symlink/UltiSnips/javascript_module.snippets
new file mode 100644
index 0000000..d20bcff
--- /dev/null
+++ b/vim/vim.symlink/UltiSnips/javascript_module.snippets
@@ -0,0 +1,10 @@
+snippet mimport
+import ${1:${2:default}, }${2:\{
+ ${3:...things}
+\}} from ${4:'${5:module}'};
+$0
+endsnippet
+
+snippet mdep
+${1:dependency}${2: as ${3:alias}},
+endsnippet
diff --git a/vim/vim.symlink/UltiSnips/javascript_react.snippets b/vim/vim.symlink/UltiSnips/javascript_react.snippets
new file mode 100644
index 0000000..e2c36f9
--- /dev/null
+++ b/vim/vim.symlink/UltiSnips/javascript_react.snippets
@@ -0,0 +1,50 @@
+snippet action
+export const type = '${1:`!p snip.rv = snip.basename`}';
+
+export default (${2:...args}) => (\{
+ type,${3:
+ payload: \{
+ ${2/,?( |$)/,\n $1$1/g}\},}
+\});$0
+endsnippet
+
+snippet testaction
+import test from 'tape';
+
+import ${1/-(\w)/\u$1/g}, \{
+ type,
+\} from '../../src/actions/${1:`!p snip.rv = snip.basename`}';
+
+test('${1/-(\w)/\u$1/g} is a function', (t) => \{
+ const actual = typeof ${1/-(\w)/\u$1/g};
+ const expected = 'function';
+
+ t.equal(
+ actual, expected,
+ '${1/-(\w)/\u$1/g} should be a function'
+ );
+
+ t.end();
+\});
+
+test('${1/-(\w)/\u$1/g} returns the correct action', (t) => \{
+ const actual = ${1/-(\w)/\u$1/g}();
+ const expected = \{ type \};
+
+ t.deepEqual(
+ actual, expected,
+ 'Action not of expected shape'
+ );
+ t.end();
+\});
+endsnippet
+
+snippet impaction
+import ${1/-(\w)/\u$1/g}, \{
+ type as ${1/-(\w)/\u$1/g}Type,
+\} from './${1:action-file-name}';
+
+${1/-(\w)/\u$1/g}.type = ${1/-(\w)/\u$1/g}Type;
+
+export \{ ${1/-(\w)/\u$1/g} \};
+endsnippet
diff --git a/vim/vim.symlink/UltiSnips/php.snippets b/vim/vim.symlink/UltiSnips/php.snippets
index 4e21cc0..e0afb80 100644
--- a/vim/vim.symlink/UltiSnips/php.snippets
+++ b/vim/vim.symlink/UltiSnips/php.snippets
@@ -35,7 +35,7 @@ namespace ${2:`!p snip.rv = get_namespace(full_path(path))`};
${3:// Use...}
-class ${4:`!p snip.rv = snip.basename`}${5: extends ${6:ParentInterface}}
+interface ${4:`!p snip.rv = snip.basename`}${5: extends ${6:ParentInterface}}
\{
${0:// Interface...}
\}
diff --git a/vim/vim.symlink/UltiSnips/php_magento.snippets b/vim/vim.symlink/UltiSnips/php_magento.snippets
index 591fb1f..159ff02 100644
--- a/vim/vim.symlink/UltiSnips/php_magento.snippets
+++ b/vim/vim.symlink/UltiSnips/php_magento.snippets
@@ -79,7 +79,7 @@ use Magento\\Framework\\View\\Element\\Template;
use Magento\\Framework\\View\\Element\\Template\\Context;
${3:// Use...}
-class ${4:`!p snip.rv = snip.basename`}extends ${6:Template}${7: implements ${8:SomeInterface, OtherInterface}}
+class ${4:`!p snip.rv = snip.basename`} extends ${6:Template}${7: implements ${8:SomeInterface, OtherInterface}}
\{
${0:// Implementation...}
\}
diff --git a/vim/vim.symlink/UltiSnips/xml.snippets b/vim/vim.symlink/UltiSnips/xml.snippets
index eba069c..542cfd2 100644
--- a/vim/vim.symlink/UltiSnips/xml.snippets
+++ b/vim/vim.symlink/UltiSnips/xml.snippets
@@ -7,3 +7,42 @@ snippet mmodxml
endsnippet
+
+snippet mdixml
+
+
+ $0
+
+endsnippet
+
+snippet mwidgets
+
+
+ $0
+
+endsnippet
+
+snippet mwidget
+
+
+ $7
+
+ $0
+
+
+endsnippet
+
+snippet mwidgetparam
+
+
+ $7
+
+endsnippet
diff --git a/vim/vim.symlink/colors/maxbucknell.vim b/vim/vim.symlink/colors/maxbucknell.vim
index daed03e..caacdac 100644
--- a/vim/vim.symlink/colors/maxbucknell.vim
+++ b/vim/vim.symlink/colors/maxbucknell.vim
@@ -29,10 +29,7 @@ hi Normal cterm=NONE ctermfg=7 ctermbg=NONE
hi Type cterm=NONE ctermfg=7 ctermbg=NONE
hi Keyword cterm=NONE ctermfg=7 ctermbg=NONE
hi Operator cterm=NONE ctermfg=7 ctermbg=NONE
-hi String cterm=NONE ctermfg=7 ctermbg=NONE
-hi Number cterm=NONE ctermfg=7 ctermbg=NONE
hi Special cterm=NONE ctermfg=7 ctermbg=NONE
-hi Boolean cterm=NONE ctermfg=7 ctermbg=NONE
hi Statement cterm=NONE ctermfg=7 ctermbg=NONE
hi Identifier cterm=NONE ctermfg=7 ctermbg=NONE
hi Constant cterm=NONE ctermfg=7 ctermbg=NONE
@@ -60,13 +57,20 @@ hi xmlAttribPunct cterm=NONE ctermfg=7 ctermbg=NONE
" Miscellaneous leftovers
hi helpNote cterm=NONE ctermfg=7 ctermbg=NONE
-hi MatchParen cterm=NONE ctermfg=5 ctermbg=NONE
+hi MatchParen cterm=NONE ctermfg=7 ctermbg=5
+
+" Scalars are cyan
+hi String cterm=NONE ctermfg=6 ctermbg=NONE
+hi Number cterm=NONE ctermfg=6 ctermbg=NONE
+hi Boolean cterm=NONE ctermfg=6 ctermbg=NONE
" Comments are green
hi Comment cterm=NONE ctermfg=2 ctermbg=NONE
+" Preprocessor statements aren't comments.
hi PreProc cterm=NONE ctermfg=2 ctermbg=NONE
+" JSDoc comments are comments.
hi jsDocTags cterm=NONE ctermfg=2 ctermbg=NONE
hi jsDocType cterm=NONE ctermfg=2 ctermbg=NONE
hi jsDocParam cterm=NONE ctermfg=2 ctermbg=NONE
diff --git a/vim/vimrc.symlink b/vim/vimrc.symlink
index 7b7e8e3..779fdd1 100644
--- a/vim/vimrc.symlink
+++ b/vim/vimrc.symlink
@@ -89,6 +89,7 @@ endfunction
function! s:FileListCommand()
if filereadable(g:pick_index_file) == 0
+ echo "Rebuilding"
call system("find * -type f -o -type l > " . g:pick_index_file)
endif
@@ -124,11 +125,29 @@ nnoremap b :call PickBuffer()
nnoremap n :call PickFileVerticalSplit()
nnoremap :call RefreshPickIndex()
+" Navigate to test, and back
+
+" Find test counterpart.
+"
+" This works by replacing src/ with test/, and test/ with src/
+function! FindTestFilename(filename)
+ " Replace src/ with t_est/
+ let first = substitute(a:filename, 'src/', 't_est/', '')
+ " Replace test/ with src/
+ let second = substitute(first, 'test/', 'src/', '')
+ " Replace t_est/ with test/
+ let third = substitute(second, 't_est/', 'test/', '')
+
+ return third
+endfunction
+
+nnoremap :exec ":e " . FindTestFilename(expand('%'))
+
" Git blame
"
" Replace the buffer contents with git blame.
" Hit u to undo
-nnoremap a :1,$!git blame %
+nnoremap a :%!git blame %
" Tab config options
"
@@ -405,7 +424,7 @@ augroup vimrcEx
\ endif
" Language whitespace settings
- autocmd FileType less,snippets,javascript,json,c,xml,java,php,python setl et sw=4 sts=4
+ autocmd FileType less,snippets,json,c,xml,java,php,python setl et sw=4 sts=4
autocmd FileType make,markdown setl noet sw=8 sts=8 ts=8
" Hard wrap prose
@@ -449,6 +468,9 @@ let g:syntastic_php_phpcs_args = '--standard=PSR2'
let g:syntastic_python_python_exec = 'python3'
+" JSX in mah JavaScript
+let g:jsx_ext_required = 0
+
" Copy visual selection to clipboard.
noremap y "*y