summaryrefslogtreecommitdiffstats
path: root/autoload/elm/util.vim
blob: 6d1014e00a83c3b37c5e643d7bfb37e92bd93032 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'elm') != -1
  finish
endif

" IsWin returns 1 if current OS is Windows or 0 otherwise
fun! elm#util#IsWin() abort
  let l:win = ['win16', 'win32', 'win32unix', 'win64', 'win95']
  for l:w in l:win
    if (has(l:w))
      return 1
    endif
  endfor

  return 0
endf

fun! elm#util#CheckBin(bin, url) abort
  let l:binpath = substitute(a:bin, '^\s*\(.\{-}\)\s*$', '\1', '')

  if executable(l:binpath)
    return l:binpath
  endif

  call elm#util#EchoWarning('elm-vim:', 'could not find ' . l:binpath . ' [' . a:url . ']')

  return ''
endf

" Determines the browser command to use
fun! s:get_browser_command() abort
  let l:elm_browser_command = get(g:, 'elm_browser_command', '')
  if l:elm_browser_command ==? ''
    if elm#util#IsWin()
      let l:elm_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%'
    elseif has('mac') || has('macunix') || has('gui_macvim') || system('uname') =~? '^darwin'
      let l:elm_browser_command = 'open %URL%'
    elseif executable('xdg-open')
      let l:elm_browser_command = 'xdg-open %URL%'
    elseif executable('firefox')
      let l:elm_browser_command = 'firefox %URL% &'
    else
      let l:elm_browser_command = ''
    endif
  endif
  return l:elm_browser_command
endf

" OpenBrowser opens a url in the default browser
fun! elm#util#OpenBrowser(url) abort
  let l:cmd = s:get_browser_command()
  if len(l:cmd) == 0
    redraw
    echohl WarningMsg
    echo "It seems that you don't have general web browser. Open URL below."
    echohl None
    echo a:url
    return
  endif
  if l:cmd =~? '^!'
    let l:cmd = substitute(l:cmd, '%URL%', '\=shellescape(a:url)', 'g')
    silent! exec l:cmd
  elseif l:cmd =~# '^:[A-Z]'
    let l:cmd = substitute(l:cmd, '%URL%', '\=a:url', 'g')
    exec l:cmd
  else
    let l:cmd = substitute(l:cmd, '%URL%', '\=shellescape(a:url)', 'g')
    call system(l:cmd)
  endif
endf

" DecodeJSON decodes a string of json into a viml object
fun! elm#util#DecodeJSON(s) abort
  let l:true = 1
  let l:false = 0
  let l:null = 0
  return eval(a:s)
endf

" Remove ANSI escape characters used for highlighting purposes
fun! s:strip_color(msg) abort
  return substitute(a:msg, '\e\[[0-9;]\+[mK]', '', 'g')
endf

" Print functions
fun! elm#util#Echo(title, msg) abort
  redraws! | echon a:title . ' ' | echohl Identifier | echon s:strip_color(a:msg) | echohl None
endf

fun! elm#util#EchoSuccess(title, msg) abort
  redraws! | echon a:title . ' ' | echohl Function | echon s:strip_color(a:msg) | echohl None
endf

fun! elm#util#EchoWarning(title, msg) abort
  redraws! | echon a:title . ' ' | echohl WarningMsg | echon s:strip_color(a:msg) | echohl None
endf

fun! elm#util#EchoError(title, msg) abort
  redraws! | echon a:title . ' ' | echohl ErrorMsg | echon s:strip_color(a:msg) | echohl None
endf

fun! elm#util#EchoLater(func_name, title, msg) abort
  let s:echo_func_name = a:func_name
  let s:echo_title = a:title
  let s:echo_msg = a:msg
endf

fun! elm#util#EchoStored() abort
  if exists('s:echo_func_name') && exists('s:echo_title') && exists('s:echo_msg')
    call elm#util#{s:echo_func_name}(s:echo_title, s:echo_msg)
    unlet s:echo_func_name
    unlet s:echo_title
    unlet s:echo_msg
  endif
endf

function! elm#util#GoToModule(name)
  if empty(a:name) | return | endif
  if empty(matchstr(a:name, '^Native\.'))
    let l:extension = '.elm'
  else
    let l:extension = '.js'
  endif
  let l:rel_path = substitute(a:name, '\.', '/', 'g') . l:extension
  let l:root = elm#FindRootDirectory()

  let l:module_file = s:findLocalModule(l:rel_path, l:root)
  if !filereadable(l:module_file)
    let l:module_file = s:findDependencyModule(l:rel_path, l:root)
  endif

  if filereadable(l:module_file)
    exec 'edit ' . fnameescape(l:module_file)
  else
    return s:error("Can't find module \"" . a:name . "\"")
  endif
endfunction

function! s:findLocalModule(rel_path, root)
  let l:old_match = findfile('elm-package.json', a:root . ';')
  let l:new_match = findfile('elm.json', a:root . ';')
  if !empty(l:new_match)
    let l:package_json = l:new_match
  elseif !empty(l:old_match)
    let l:package_json = l:old_match
  endif
  if exists('*json_decode')
    let l:package = json_decode(readfile(l:package_json))
    let l:source_roots = l:package['source-directories']
  else
    " This is a fallback for vim's which do not support json_decode.
    " It simply only looks in the 'src' subdirectory and fails otherwise.
    let l:source_roots = ['src']
  end
  for l:source_root in l:source_roots
    let l:file_path = a:root . '/' . l:source_root . '/' . a:rel_path
    if !filereadable(l:file_path)
      continue
    endif
    return l:file_path
  endfor
endfunction

function! s:findDependencyModule(rel_path, root)
  " If we are a dependency ourselves, we need to check our siblings.
  " This is because elm package doesn't install dependencies recursively.
  let l:root = substitute(a:root, '\/elm-stuff/packages.\+$', '', '')

  " We naively craws the dependencies dir for any fitting module name.
  " If it exists, we'll find it. If multiple filenames match,
  " there's a chance we return the wrong one.
  let l:module_paths = glob(l:root . '/elm-stuff/packages/**/' . a:rel_path, 0, 1)
  if len(l:module_paths) > 0
    return l:module_paths[0]
  endif
endfunction

" Using the built-in :echoerr prints a stacktrace, which isn't that nice.
" From: https://github.com/moll/vim-node/blob/master/autoload/node.vim
function! s:error(msg)
	echohl ErrorMsg
	echomsg a:msg
	echohl NONE
	let v:errmsg = a:msg
endfunction