server.vim 10.9 KB
Newer Older
C
Cosmin Popescu 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
"============================================================================"
"
"  Vim SQL Workbench/J Implementation
"
"  Copyright (c) Cosmin Popescu
"
"  Author:      Cosmin Popescu <cosminadrianpopescu at gmail dot com>
"  Version:     1.00 (2015-01-08)
"  Requires:    Vim 7
"  License:     GPL
"
"  Description:
"
"  Provides SQL database access to any DBMS supported by SQL Workbench/J. The
"  only dependency is SQL Workbench/J. Also includes powefull intellisense
"  autocomplete based on the current selected database
"
"============================================================================"

let s:current_file = expand('<sfile>:p:h')
C
Cosmin Popescu 已提交
21
let s:nvim = has("nvim")
C
Cosmin Popescu 已提交
22 23 24
let s:channel_handlers = {}
let s:pattern_prompt_begin = '\v^([a-zA-Z_0-9\.]+(\@[a-zA-Z_0-9\/\-]+)*\>[ \s\t]*)+'
let s:pattern_prompt = s:pattern_prompt_begin . '$'
C
Cosmin Popescu 已提交
25
let s:pattern_wait_input = '\v^([a-zA-Z_][a-zA-Z0-9_]*( \[[^\]]+\])?: |([^\>]+\> )?([^\>]+\> )*Username|([^\>]+\> )*Password: |([^\>]+\>[ ]+)?Do you want to run the command [A-Z]+\? \(Yes\/No\/All\)[ ]+)$'
C
Cosmin Popescu 已提交
26
let s:params_history = []
C
Cosmin Popescu 已提交
27
let s:pattern_new_connection = '\v^Connection to "([^"]+)" successful$'
C
Cosmin Popescu 已提交
28
let s:timer = {'id': -1, 'sec' : 0}
C
Cosmin Popescu 已提交
29

C
Cosmin Popescu 已提交
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
function! sw#server#get_channel_pid(vid, channel, message)
    for handler_item in items(s:channel_handlers)
        let handler = handler_item[1]
        if handler.vid == a:vid
            for line in split(a:message, '\v[\r\n]')
                let pattern = '\v^([0-9]+) .*vid\=' . a:vid . '$'
                if line =~ pattern
                    let handler.pid = substitute(line, pattern, '\1', 'g')
                    return
                endif
            endfor
        endif
    endfor
endfunction

function! s:get_channel_pid(channel)
    let cmd = 'jps -m'
    if !s:nvim
        let Func = function('sw#server#get_channel_pid', [s:channel_handlers[a:channel].vid])
        let job = job_start(cmd, {'in_mode': 'raw', 'out_mode': 'raw'})
        let channel = job_getchannel(job)
        call ch_setoptions(channel, {'callback': Func})
    else
        let job = jobstart(cmd, {'on_stdout': function('sw#server#nvim_get_channel_pid')})
    endif
endfunction

C
Cosmin Popescu 已提交
57 58
function! s:log_init(channel)
    if g:sw_log_to_file
C
Cosmin Popescu 已提交
59
        let s:channel_handlers[a:channel].log = g:sw_tmp . '/' . sw#servername() . '-' . substitute(fnamemodify(bufname('%'), ':t'), '\.', '-', 'g')
C
Cosmin Popescu 已提交
60 61 62
    else
        let s:channel_handlers[a:channel].log = ''
    endif
C
Cosmin Popescu 已提交
63 64
endfunction

C
Cosmin Popescu 已提交
65 66 67 68 69 70 71
function! s:log_channel(channel, txt)
    if g:sw_log_to_file
        let file = s:channel_handlers[a:channel].log
        let mode = filereadable(file) ? 'ab' : 'wb'
        call writefile(split(a:txt, "\n"), file, mode)
    else
        let s:channel_handlers[a:channel].log .= a:txt
C
Cosmin Popescu 已提交
72
    endif
C
Cosmin Popescu 已提交
73
endfunction
C
Cosmin Popescu 已提交
74

C
Cosmin Popescu 已提交
75 76 77 78
function! sw#server#channel_log(channel)
    return s:channel_handlers[a:channel].log
endfunction

C
Cosmin Popescu 已提交
79 80 81 82 83 84 85 86
function! sw#server#nvim_handle_message(job, lines, ev)
    if a:ev == 'stdout'
        let msg = ''
        for line in a:lines
            let msg .= (msg == '' ? '' : "\n") . line
        endfor

        call sw#server#handle_message(a:job, msg)
C
Cosmin Popescu 已提交
87 88
    elseif a:ev == 'exit'
        call sw#server#disconnect_buffer(a:job)
C
Cosmin Popescu 已提交
89 90 91
    endif
endfunction

C
Cosmin Popescu 已提交
92 93 94 95 96 97
function! sw#server#prompt_for_value(channel, line, timer_id)
    let value = input('SQL Workbench/J is asking for input for ' . a:line . ' ', '')
    call add(s:params_history, {'prompt': a:line, 'value': value})
    call ch_sendraw(a:channel, value . "\n")
endfunction

C
Cosmin Popescu 已提交
98
function! sw#server#handle_message(channel, msg)
C
Cosmin Popescu 已提交
99 100 101
    if has_key(s:channel_handlers[a:channel], 'pid') && s:channel_handlers[a:channel].pid == ''
        call s:get_channel_pid(a:channel)
    endif
C
Cosmin Popescu 已提交
102 103 104 105 106 107 108 109 110 111 112 113
    call s:log_channel(a:channel, a:msg)
    let lines = split(substitute(a:msg, "\r", "", 'g'), "\n")
    let got_prompt = 0
    let max_length = 0
    let text = ''
    for line in lines
        let line = substitute(line, '\v^(\.\.\> )*', '', 'g')
        let text .= (text == '' ? '' : "\n") . substitute(line, s:pattern_prompt_begin, '', 'g')
        if line =~ s:pattern_prompt
            let got_prompt = 1
        endif
        if line =~ s:pattern_wait_input && !(line =~ '\v^Catalog: $') && !(line =~ '\v^Schema: $')
C
Cosmin Popescu 已提交
114
            if s:nvim
C
Cosmin Popescu 已提交
115 116
                let value = input('SQL Workbench/J is asking for input for ' . line . ' ', '')
                call add(s:params_history, {'prompt': line, 'value': value})
C
Cosmin Popescu 已提交
117 118
                call jobsend(b:sw_channel, value . "\n")
            else
C
Cosmin Popescu 已提交
119 120 121
                let Func = function('sw#server#prompt_for_value', [a:channel, line])
                let got_prompt = 1
                let timer_id = timer_start(500, Func)
C
Cosmin Popescu 已提交
122
            endif
C
Cosmin Popescu 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
        endif

        if line =~ s:pattern_new_connection 
            let s:channel_handlers[a:channel].current_url = substitute(line, s:pattern_new_connection, '\1', 'g')
        endif
    endfor
    let s:channel_handlers[a:channel].text .= text . "\n"
    if got_prompt
        let type = s:channel_handlers[a:channel].type
        if (type == 'sqlwindow')
            if s:channel_handlers[a:channel].tmp_handler != ''
                let Func = function(s:channel_handlers[a:channel].tmp_handler)
                call Func(s:channel_handlers[a:channel].text)
                let s:channel_handlers[a:channel].tmp_handler = ''
            else
                call sw#sqlwindow#message_handler(a:channel, s:channel_handlers[a:channel].text)
            endif
        elseif (type == 'dbexplorer')
            call sw#dbexplorer#message_handler(a:channel, s:channel_handlers[a:channel].text)
        endif

        let s:channel_handlers[a:channel].text = ''
        call s:init_timer()
C
Cosmin Popescu 已提交
146
    endif
C
Cosmin Popescu 已提交
147
endfunction
C
Cosmin Popescu 已提交
148

C
Cosmin Popescu 已提交
149
function! s:start_sqlwb(type)
C
Cosmin Popescu 已提交
150 151
    let vid = substitute(v:servername, '\v\/', '-', 'g') . sw#generate_unique_id()
    let cmd = [g:sw_exe, '-feedback=true', '-showProgress=false', '-showTiming=true', '-nosettings', '-variable=vid=' . vid]
C
Cosmin Popescu 已提交
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

    let valid_exe = 1
    if !filereadable(g:sw_exe)
        echom g:sw_exe . " is not readable. Make sure the setting g:sw_exe is set and the file exists."
        let valid_exe = 0
    endif
    if match(getfperm(g:sw_exe), "r.x.*") ==# -1
        echom g:sw_exe . " is not executable. Make sure the permissions are set correctly."
        let valid_exe = 0
    endif

    if !valid_exe
        return
    endif

C
Cosmin Popescu 已提交
167 168
    if !s:nvim
        let job = job_start(cmd, {'in_mode': 'raw', 'out_mode': 'raw'})
C
Cosmin Popescu 已提交
169 170
        let pid = substitute(job, '\v^process ([0-9]+).*$', '\1', 'g')
        let pid = ''
C
Cosmin Popescu 已提交
171
        let channel = job_getchannel(job)
C
Cosmin Popescu 已提交
172
        call ch_setoptions(channel, {'callback': 'sw#server#handle_message', 'close_cb': 'sw#server#disconnect_buffer'})
C
Cosmin Popescu 已提交
173 174
    else
        let channel = jobstart(cmd, {'on_stdout': function('sw#server#nvim_handle_message'), 'on_stderr': function('sw#server#nvim_handle_message'), 'on_exit': function('sw#server#nvim_handle_message')})
C
Cosmin Popescu 已提交
175
        let pid = jobpid(channel)
C
Cosmin Popescu 已提交
176 177
    endif

C
Cosmin Popescu 已提交
178
    let s:channel_handlers[channel] = {'text': '', 'type': a:type, 'buffer': fnamemodify(bufname('%'), ':p'), 'current_url': '', 'tmp_handler': '', 'vid': vid, 'pid': pid}
C
Cosmin Popescu 已提交
179 180 181
    call s:log_init(channel)

    return channel
C
Cosmin Popescu 已提交
182 183
endfunction

C
Cosmin Popescu 已提交
184
function! sw#server#connect_buffer(...)
C
Cosmin Popescu 已提交
185 186 187
    let file = bufname('%')
    let command = 'e'
    if (a:0 >= 2)
C
Cosmin Popescu 已提交
188 189
        let file = a:2
        let command = a:1
C
Cosmin Popescu 已提交
190 191 192
    elseif a:0 >= 1
        let command = a:1
    endif
C
Cosmin Popescu 已提交
193

C
Cosmin Popescu 已提交
194 195
    execute command . " " . file
    call sw#session#init_section()
C
Cosmin Popescu 已提交
196

C
Cosmin Popescu 已提交
197 198 199 200 201
    if (!exists('b:sw_channel'))
        let b:sw_channel = s:start_sqlwb('sqlwindow')
    endif

    call sw#sqlwindow#open_buffer(file, command)
C
Cosmin Popescu 已提交
202 203
endfunction

C
Cosmin Popescu 已提交
204 205 206 207
function! sw#server#execute_sql(sql, ...)
    let channel = ''
    if (exists('b:sw_channel'))
        let channel = b:sw_channel
C
Cosmin Popescu 已提交
208
    endif
C
Cosmin Popescu 已提交
209 210 211 212 213 214
    let callback = ''
    if a:0 >= 2
        let channel = a:1
        let callback = a:2
    elseif a:0 >= 1
        let channel = a:1
C
Cosmin Popescu 已提交
215
    endif
C
Cosmin Popescu 已提交
216 217 218
    if !s:nvim
        if ch_status(channel) != 'open'
            call sw#display_error("The channel is not open. This means that SQL Workbench/J instance for this answer does not responsd anymore. Please do again SWSqlBufferConnect")
C
Cosmin Popescu 已提交
219 220 221
            if exists('b:sw_channel')
                unlet b:sw_channel
            endif
C
Cosmin Popescu 已提交
222 223
            return ''
        endif
C
Cosmin Popescu 已提交
224
    endif
C
Cosmin Popescu 已提交
225 226 227 228
    let text = a:sql . "\n"
    call s:log_channel(channel, text)
    if callback != ''
        let s:channel_handlers[channel].tmp_handler = callback
C
Cosmin Popescu 已提交
229
    endif
C
Cosmin Popescu 已提交
230 231 232 233 234
    if s:nvim
        call jobsend(channel, text)
    else
        call ch_sendraw(channel, text)
    endif
C
Cosmin Popescu 已提交
235 236 237
    if g:sw_command_timer
        call s:init_timer()
        let s:timer.id = timer_start(1000, 'sw#server#timer', {'repeat': -1})
C
Cosmin Popescu 已提交
238
    endif
C
Cosmin Popescu 已提交
239
endfunction
C
Cosmin Popescu 已提交
240

C
Cosmin Popescu 已提交
241
function! s:init_timer()
C
Cosmin Popescu 已提交
242
    if s:timer.id != -1
C
Cosmin Popescu 已提交
243
        call timer_stop(s:timer.id)
C
Cosmin Popescu 已提交
244
    endif
C
Cosmin Popescu 已提交
245
    let s:timer = {'id': -1, 'sec': 0}
C
Cosmin Popescu 已提交
246 247
endfunction

C
Cosmin Popescu 已提交
248 249 250
function! sw#server#timer(timer)
    let s:timer.sec += 1
    echo "Query time: " . s:timer.sec . " seconds"
C
Cosmin Popescu 已提交
251 252
endfunction

C
Cosmin Popescu 已提交
253 254 255 256 257 258 259 260 261
function! sw#server#disconnect_buffer(...)
    let channel = ''
    if (exists('b:sw_channel'))
        let channel = b:sw_channel
        unlet b:sw_channel
    endif
    if a:0
        let channel = a:1
    endif
C
Cosmin Popescu 已提交
262 263 264
    if channel == ''
        return
    endif
C
Cosmin Popescu 已提交
265 266 267 268 269 270 271 272 273 274
    if (!s:nvim && ch_status(channel) == 'open') || s:nvim
        try
            call sw#server#execute_sql('exit', channel)
        catch
        endtry
    endif
    let key = substitute(channel, '\v^channel ([0-9]+).*$', 'channel \1 open', 'g')
    if has_key(s:channel_handlers, key)
        unlet s:channel_handlers[key]
    endif
C
Cosmin Popescu 已提交
275
    call s:init_timer()
C
Cosmin Popescu 已提交
276

C
Cosmin Popescu 已提交
277 278 279
    if exists('g:sw_airline_support') && g:sw_airline_support == 1
        call airline#update_statusline()
    endif
C
Cosmin Popescu 已提交
280
endfunction
C
Cosmin Popescu 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299

function! sw#server#kill_statement(...)
    let channel = ''
    if exists('b:sw_channel')
        let channel = b:sw_channel
    endif
    if a:0
        let channel = a:1
    endif

    if has_key(s:channel_handlers, channel) && has_key(s:channel_handlers[channel], 'pid')
        let cmd = 'kill -SIGINT ' . s:channel_handlers[channel].pid
        if !s:nvim
            call job_start(cmd)
        else
            call jobstart(cmd)
        endif
    endif
endfunction
C
Cosmin Popescu 已提交
300

C
Cosmin Popescu 已提交
301 302 303 304
function! sw#server#get_buffer_url(buffer)
    for key in keys(s:channel_handlers)
        if s:channel_handlers[key]['buffer'] == a:buffer
            return s:channel_handlers[key]['current_url']
C
Cosmin Popescu 已提交
305 306
        endif
    endfor
C
Cosmin Popescu 已提交
307 308

    return ''
C
Cosmin Popescu 已提交
309 310
endfunction

C
Cosmin Popescu 已提交
311 312 313 314 315 316 317 318
function! sw#server#get_active_connections()
    let result = ''
    for key in keys(s:channel_handlers)
        let url = s:channel_handlers[key]['current_url']
        let result .= (result == '' ? '' : "\n") . s:channel_handlers[key]['buffer'] . ' - ' . (url == '' ? 'NOT CONNECTED' : url)
    endfor

    return result == '' ? 'No active sql workbench buffers' : result
C
Cosmin Popescu 已提交
319
endfunction
C
Cosmin Popescu 已提交
320

C
Cosmin Popescu 已提交
321 322 323 324 325 326 327 328 329 330
function! sw#server#tmp()
    return s:channel_handlers
endfunction

function! sw#server#open_dbexplorer(profile)
    let channel = s:start_sqlwb('dbexplorer')
    let command = sw#get_connect_command(a:profile)
    call sw#server#execute_sql(command, channel)

    return channel
C
Cosmin Popescu 已提交
331
endfunction
C
Cosmin Popescu 已提交
332 333 334 335

function! sw#server#get_parameters_history()
    return s:params_history
endfunction