From ab8417152d8c791444a714ca5dc900cea2746b4c Mon Sep 17 00:00:00 2001 From: Cosmin Popescu Date: Tue, 1 Nov 2016 20:03:25 +0100 Subject: [PATCH] version 6.2 --- autoload/sw/dbexplorer.vim | 94 +++++++++++++++++++++++++++++++++++-- autoload/sw/server.vim | 95 +++++++++++++++++++++++++++++++++----- autoload/sw/sqlwindow.vim | 9 ++-- resources/airline/sw.vim | 2 +- resources/dbexplorer.vim | 1 + 5 files changed, 181 insertions(+), 20 deletions(-) diff --git a/autoload/sw/dbexplorer.vim b/autoload/sw/dbexplorer.vim index 93214de..63a061f 100644 --- a/autoload/sw/dbexplorer.vim +++ b/autoload/sw/dbexplorer.vim @@ -24,6 +24,9 @@ endif let s:profiles = {} let s:events = {'panels': {'before': {}, 'after': {}}, 'tabs': {'before': {}, 'after': {}}} let s:last_command = {} +let s:cache = {} +let s:cache_filter = "!(v:val =~ '\\v^Execution time')" +let s:cache_message = 'Execution time (from cache)' " Local functions{{{1 " Iterates in the tabs array{{{2 @@ -188,13 +191,41 @@ function! s:process_result_1(result, shortcut, title) endif endfunction +function! s:add_to_cache(shortcut, lines) + if !has_key(s:cache, b:profile) + let s:cache[b:profile] = {} + endif + let s:cache[b:profile][a:shortcut] = filter(copy(a:lines), s:cache_filter) +endfunction + +function! s:get_from_cache(shortcut) + if !has_key(s:cache, b:profile) || !has_key(s:cache[b:profile], a:shortcut) + return [] + endif + + return s:cache[b:profile][a:shortcut] +endfunction + +function! s:is_in_cache(shortcut, lines) + let f = 'v:val != "" && v:val != "' . s:cache_message . '"' + return filter(copy(s:get_from_cache(a:shortcut)), f) == filter(copy(filter(copy(a:lines), s:cache_filter)), f) +endfunction + " Change a tab{{{2 function! sw#dbexplorer#change_tab(command, shortcut, title) let command = s:process_events('tabs', 'before', a:shortcut, '', a:command) let s:last_command = {'command': command, 'shortcut': a:shortcut, 'title': a:title, 'type': 1} + if len(s:get_from_cache(a:shortcut)) > 0 + let arr = copy(s:get_from_cache(a:shortcut)) + call s:process_result_1(add(arr, s:cache_message), a:shortcut, a:title) + endif call sw#dbexplorer#do_command(command) endfunction +function! sw#dbexplorer#tmp() + return s:cache +endfunction + function! sw#dbexplorer#do_command(sql) if !exists('b:profile') || !exists('b:sw_channel') return @@ -285,7 +316,12 @@ function! s:change_panel(command, shortcut, title, tab_shortcut) let cmd = substitute(cmd, '\v\%' . i . '\%', column, 'g') let i = i + 1 endfor - let s:last_command = {'tab_shortcut': a:tab_shortcut, 'shortcut': a:shortcut, 'cmd': cmd, 'type': 2} + let s:last_command = {'tab_shortcut': a:tab_shortcut, 'shortcut': a:shortcut, 'cmd': cmd, 'type': 2, 'object': object} + + if len(s:get_from_cache(a:tab_shortcut . object . a:shortcut)) > 0 + let arr = copy(s:get_from_cache(a:tab_shortcut . object . a:shortcut)) + call s:process_result_2(add(arr, s:cache_message), a:tab_shortcut, a:shortcut, cmd) + endif call sw#dbexplorer#do_command(cmd) endfunction @@ -418,15 +454,36 @@ function! s:process_events(which, when, tab_shortcut, shortcut, result) return result endfunction +function! s:check_cache(shortcut, result) + if s:is_in_cache(a:shortcut, a:result) + return 1 + endif + + call s:add_to_cache(a:shortcut, a:result) + + return 0 +endfunction + " Handles a message from the server{{{2 function! sw#dbexplorer#message_handler(channel, message) let result = split(a:message, "\n") + if has_key(s:last_command, 'shortcut') + let shortcut = s:last_command.shortcut + if has_key(s:last_command, 'tab_shortcut') && has_key(s:last_command, 'object') + let shortcut = s:last_command.tab_shortcut . s:last_command.object . shortcut + endif + endif + if s:last_command.type == 1 let result = s:process_events('tabs', 'after', s:last_command.shortcut, '', result) - call s:process_result_1(result, s:last_command.shortcut, s:last_command.title) + if !s:check_cache(shortcut, result) + call s:process_result_1(result, s:last_command.shortcut, s:last_command.title) + endif elseif s:last_command.type == 2 let result = s:process_events('panels', 'after', s:last_command.tab_shortcut, s:last_command.shortcut, result) - call s:process_result_2(result, s:last_command.tab_shortcut, s:last_command.shortcut, s:last_command.cmd) + if !s:check_cache(shortcut, result) + call s:process_result_2(result, s:last_command.tab_shortcut, s:last_command.shortcut, s:last_command.cmd) + endif elseif s:last_command.type == 3 call s:process_result_1(result, '', '') endif @@ -518,4 +575,35 @@ function! sw#dbexplorer#filtered_data(result) return result endfunction +function! sw#dbexplorer#fold_columns(result) + let name = bufname('%') + call sw#goto_window('__SQL__-' . b:profile) + + setlocal foldmethod=expr + setlocal foldexpr=sw#dbexplorer#do_fold_columns(v:lnum) + normal zR + + return a:result +endfunction + +function! sw#dbexplorer#do_fold_columns(lnum) + if (a:lnum == 1) + let b:fold_level = 0 + endif + if getline(a:lnum) =~ '\v^---- ' + let b:fold_level += 1 + return '>' . b:fold_level + endif + if getline(a:lnum) =~ '\v^[ \s\t\n\r]*$' + let result = '<' . b:fold_level + let b:fold_level -= 1 + if b:fold_level < 0 + let b:fold_level = 0 + endif + return result + endif + + return -1 +endfunction + " vim:fdm=marker diff --git a/autoload/sw/server.vim b/autoload/sw/server.vim index 3256651..64b96cd 100644 --- a/autoload/sw/server.vim +++ b/autoload/sw/server.vim @@ -22,11 +22,38 @@ let s:nvim = has("nvim") 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 . '$' -let s:pattern_wait_input = '\v^([a-zA-Z_][a-zA-Z0-9_]*( \[[^\]]+\])?: |([^\>]+\> )?([^\>]+\> )*Username|([^\>]+\> )*Password: |([^\>]+\>[ ]+)?Do you want to run the command UPDATE\? \(Yes\/No\/All\)[ ]+)$' +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\)[ ]+)$' let s:params_history = [] let s:pattern_new_connection = '\v^Connection to "([^"]+)" successful$' let s:timer = {'id': -1, 'sec' : 0} +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 + function! s:log_init(channel) if g:sw_log_to_file let s:channel_handlers[a:channel].log = g:sw_tmp . '/' . sw#servername() . '-' . substitute(fnamemodify(bufname('%'), ':t'), '\.', '-', 'g') @@ -57,10 +84,21 @@ function! sw#server#nvim_handle_message(job, lines, ev) endfor call sw#server#handle_message(a:job, msg) + elseif a:ev == 'exit' + call sw#server#disconnect_buffer(a:job) endif endfunction +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 + function! sw#server#handle_message(channel, msg) + if has_key(s:channel_handlers[a:channel], 'pid') && s:channel_handlers[a:channel].pid == '' + call s:get_channel_pid(a:channel) + endif call s:log_channel(a:channel, a:msg) let lines = split(substitute(a:msg, "\r", "", 'g'), "\n") let got_prompt = 0 @@ -73,12 +111,14 @@ function! sw#server#handle_message(channel, msg) let got_prompt = 1 endif if line =~ s:pattern_wait_input && !(line =~ '\v^Catalog: $') && !(line =~ '\v^Schema: $') - let value = input('SQL Workbench/J is asking for input for ' . line . ' ', '') - call add(s:params_history, {'prompt': line, 'value': value}) if s:nvim + let value = input('SQL Workbench/J is asking for input for ' . line . ' ', '') + call add(s:params_history, {'prompt': line, 'value': value}) call jobsend(b:sw_channel, value . "\n") else - call ch_sendraw(b:sw_channel, value . "\n") + let Func = function('sw#server#prompt_for_value', [a:channel, line]) + let got_prompt = 1 + let timer_id = timer_start(500, Func) endif endif @@ -107,21 +147,23 @@ function! sw#server#handle_message(channel, msg) endfunction function! s:start_sqlwb(type) - let cmd = g:sw_exe . ' -feedback=true -showProgress=false -abortOnError=false -showTiming=true' + 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] if !s:nvim let job = job_start(cmd, {'in_mode': 'raw', 'out_mode': 'raw'}) + let pid = substitute(job, '\v^process ([0-9]+).*$', '\1', 'g') + let pid = '' let channel = job_getchannel(job) - call ch_setoptions(channel, {'callback': 'sw#server#handle_message'}) + call ch_setoptions(channel, {'callback': 'sw#server#handle_message', 'close_cb': 'sw#server#disconnect_buffer'}) 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')}) + let pid = jobpid(channel) endif - let s:channel_handlers[channel] = {'text': '', 'type': a:type, 'buffer': fnamemodify(bufname('%'), ':p'), 'current_url': '', 'tmp_handler': ''} + let s:channel_handlers[channel] = {'text': '', 'type': a:type, 'buffer': fnamemodify(bufname('%'), ':p'), 'current_url': '', 'tmp_handler': '', 'vid': vid, 'pid': pid} call s:log_init(channel) return channel - - ""return job endfunction function! sw#server#connect_buffer(...) @@ -159,7 +201,9 @@ function! sw#server#execute_sql(sql, ...) 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") - unlet b:sw_channel + if exists('b:sw_channel') + unlet b:sw_channel + endif return '' endif endif @@ -200,8 +244,16 @@ function! sw#server#disconnect_buffer(...) if a:0 let channel = a:1 endif - call sw#server#execute_sql('exit', channel) - unlet s:channel_handlers[channel] + 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 call s:init_timer() if exists('g:sw_airline_support') && g:sw_airline_support == 1 @@ -209,6 +261,25 @@ function! sw#server#disconnect_buffer(...) endif endfunction +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 + function! sw#server#get_buffer_url(buffer) for key in keys(s:channel_handlers) if s:channel_handlers[key]['buffer'] == a:buffer diff --git a/autoload/sw/sqlwindow.vim b/autoload/sw/sqlwindow.vim index badf27c..576210d 100644 --- a/autoload/sw/sqlwindow.vim +++ b/autoload/sw/sqlwindow.vim @@ -749,8 +749,8 @@ function! s:display_resultsets(continous) endif endfunction -function! s:add_new_resultset(channel) - call add(b:resultsets, {'messages': [], 'lines': [], 'hidden_columns': [], 'resultset_start': 0, 'header': [], 'filters': {}, 'title': '', 'rows': 0, 'channel': a:channel}) +function! s:add_new_resultset(channel, id) + call add(b:resultsets, {'messages': [], 'lines': [], 'hidden_columns': [], 'resultset_start': 0, 'header': [], 'filters': {}, 'title': '', 'rows': 0, 'channel': a:channel, 'sql': g:sw_last_sql_query, 'id': a:id}) endfunction function! s:process_result(channel, result) @@ -770,14 +770,15 @@ function! s:process_result(channel, result) let i = 0 let mode = 'message' - call s:add_new_resultset(a:channel) + let resultset_id = sw#generate_unique_id() + call s:add_new_resultset(a:channel, resultset_id) let n = len(b:resultsets) - 1 while i < len(lines) if i + 1 < len(lines) && lines[i + 1] =~ sw#get_pattern('pattern_resultset_start') "" If we have more than one resultset in a go. if len(b:resultsets[n].lines) > 0 let n += 1 - call s:add_new_resultset(a:channel) + call s:add_new_resultset(a:channel, resultset_id) endif let mode = 'resultset' let b:resultsets[n].resultset_start = len(b:resultsets[n].lines) diff --git a/resources/airline/sw.vim b/resources/airline/sw.vim index c5c6cf2..3b3730d 100644 --- a/resources/airline/sw.vim +++ b/resources/airline/sw.vim @@ -21,7 +21,7 @@ function! airline#extensions#sw#apply(...) endif if exists('b:sw_channel') - let url = sw#server#get_buffer_url(bufname('%')) + let url = sw#server#get_buffer_url(fnamemodify(bufname('%'), ':p')) if url != '' let g:airline_section_c = s:airline_section_c . s:spc . g:airline_left_alt_sep . s:spc . url return diff --git a/resources/dbexplorer.vim b/resources/dbexplorer.vim index 300cbaf..cf50f61 100644 --- a/resources/dbexplorer.vim +++ b/resources/dbexplorer.vim @@ -38,3 +38,4 @@ let oracle_sequences = {'title': 'Sequences', 'shortcut': 'Q', 'command': 'wblis let g:SW_Tabs[':oracle'] = [oracle_dblinks, oracle_jobs, oracle_packages, oracle_schemas, oracle_sequences] call sw#dbexplorer#add_panel_event('O', 'F', 'after', 'sw#dbexplorer#filtered_data') +call sw#dbexplorer#add_panel_event('O', 'C', 'after', 'sw#dbexplorer#fold_columns') -- GitLab