changeset 1:8530ebeda72c

Adding actual db tables implementation from original script.
author Luka Sitas <lsitas@avatarasoftware.com>
date Wed, 11 Mar 2026 08:53:55 -0400
parents 238b45cc333b
children c19add1b66a9
files autoload/dbtables.vim doc/dbtables.txt plugin/dbtables.vim
diffstat 3 files changed, 437 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/autoload/dbtables.vim	Tue Mar 10 20:25:15 2026 -0400
+++ b/autoload/dbtables.vim	Wed Mar 11 08:53:55 2026 -0400
@@ -1,10 +1,261 @@
 " autoload/dbtables.vim
 " Functions are loaded on demand
 
-if exists('*dbtables#greet')
+if exists('*dbtables#*')
   finish
 endif
 
-function! dbtables#greet() abort
-  echo g:dbtables_greeting
+
+
+"=============================================
+" 				Utilities	
+"=============================================
+
+let s:query_history = []
+let s:snippets = []
+
+
+
+" - - - - - - - - - - - - - - - - - - - - - -
+" 			DB/shell interaction
+" - - - - - - - - - - - - - - - - - - - - - -
+
+" Execute shell commands
+function! s:ExecuteShellCommand(command)
+    let result = system(a:command . ' 2>&1')
+    return [v:shell_error == 0, result]
+endfunction
+
+" Execute a SQL query, directly to the db
+function! s:ExecuteDBQuery(query)
+    let command = printf('mariadb --user=%s --password=%s --database=%s --host=%s -e %s',
+                \ shellescape(g:db_user), shellescape(g:db_password),
+                \ shellescape(g:db_name), shellescape(g:db_host),
+                \ shellescape(a:query))
+    
+    let [success, result] = s:ExecuteShellCommand(command)
+    if success
+        return split(result, "\n")
+    else
+        call s:HandleDBError(result, command)
+        return []
+    endif
+endfunction
+
+" Function to execute SQL from the current buffer with parameter prompt
+function! dbtables#ExecuteSQLQuery()
+    let query = join(getline(1, '$'), "\n")
+    call s:PromptAndExecuteQuery(query)
+endfunction
+
+" Function to execute SQL from a visual selection with parameter prompt
+function! dbtables#ExecuteVisualSQLQuery() range
+    " Get the content of the selected lines as a single SQL query
+    let lines = getline(a:firstline, a:lastline)
+    let query = join(lines, "\n")
+
+    " Execute query with prompt for parameters
+    call s:PromptAndExecuteQuery(query)
+endfunction
+
+" Handle parameter prompts and execute query
+function! s:PromptAndExecuteQuery(query)
+    " Identify parameters in the form of :parameter_name
+    let pattern = ':\(\k\+\)'
+    let params = []
+    
+    " Find all matches in the query
+    let start = 0
+    while match(a:query, pattern, start) != -1
+        let match = matchstr(a:query, pattern, start)
+        if index(params, match) == -1
+            call add(params, match)
+        endif
+        let start = matchend(a:query, pattern, start)
+    endwhile
+
+    " Initialize a dictionary for parameters and their values
+    let param_values = {}
+    
+    " Prompt user for each parameter
+    for param in params
+        let value = input('Enter value for ' . param . ': ')
+        let param_values[param] = value
+    endfor
+    
+    " Replace parameters in the query with user-provided values
+    let updated_query = a:query
+    for [param, value] in items(param_values)
+        let updated_query = substitute(updated_query, param, value, 'g')
+    endfor
+
+    call add(s:query_history, updated_query)
+    call s:OpenInNewTab('SQLQueryResult', s:ExecuteDBQuery(updated_query))
+endfunction
+
+" Handle database command errors
+function! s:HandleDBError(result, command)
+    echoerr 'Shell command failed: ' . a:command
+    if a:result =~# 'Access denied'
+        echoerr 'Authentication error: Check your username and password.'
+    elseif a:result =~# 'Unknown database'
+        echoerr 'Database error: The specified database does not exist.'
+    elseif a:result =~# 'Could not connect'
+        echoerr 'Connection error: Verify host and network connectivity.'
+    elseif a:result =~# 'You have an error in your SQL syntax'
+        echoerr 'Syntax error in SQL query.'
+    else
+        echoerr 'Unexpected error: ' . a:result
+    endif
+endfunction
+
+
+
+" - - - - - - - - - - - - - - - - - - - - - -
+" 				Visuals	
+" - - - - - - - - - - - - - - - - - - - - - -
+
+" Display data in a new read only buffer
+function! s:OpenInNewTab(title, data)
+    tabnew
+    enew
+    execute 'file ' . a:title
+    if !empty(a:data)
+        call append(0, a:data)
+    else
+        call append(0, 'No data found or an error occurred.')
+    endif
+    setlocal filetype=sql buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
 endfunction
+
+
+
+"=============================================
+" 				DBTables	
+"=============================================
+" Open the list of tables in the database as a
+" buffer on the right side. Selecting a table
+" shows either the tables schema or the data
+" in the table.
+
+function! dbtables#OpenDBTablesWindow()
+    execute '34 vsplit'
+    enew
+    file DBTables
+    let tables = s:ExecuteDBQuery("SHOW TABLES;")
+    if empty(tables)
+        echo "No tables found or an error occurred."
+    else
+        call append(0, ['Available Tables:'] + tables[1:])
+        setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile
+	   		\ nomodifiable nonumber norelativenumber winfixwidth
+        nnoremap <buffer> <CR> :call <SID>ShowTablePopup()<CR>
+    endif
+endfunction
+
+" Open the database schema
+function! s:OpenTableSchema(table)
+    call s:OpenInNewTab(a:table . '_schema', s:ExecuteDBQuery('DESCRIBE ' . a:table . ';'))
+endfunction
+
+" Open the table data
+function! s:OpenTableData(table)
+    call s:OpenInNewTab(a:table, s:ExecuteDBQuery('SELECT * FROM ' . a:table . ';'))
+endfunction
+
+let s:popup_table = ""
+
+" Popup selection for table actions
+function! s:ShowTablePopup()
+    " Use Vim popup_menu if available
+    if exists('*popup_menu')
+        let s:popup_table = getline(line('.'))
+        let items = ['View Data', 'View Schema', 'Cancel']
+        call popup_menu(items, #{ 
+		\ callback: '<SID>HandlePopupSelection',
+		\ })
+        return
+    endif
+    " Popup_menu not available
+    echoerr 'Floating popup requires Vim8.2+.'
+    call s:ShowTableMenuModal()
+endfunction
+
+function! s:HandlePopupSelection(id, result)
+    let table = s:popup_table
+    call s:ClosePopup()
+    if a:result == 1
+        call s:OpenTableData(table)
+    elseif a:result == 2
+        call s:OpenTableSchema(table)
+    endif
+endfunction
+
+function! s:ClosePopup()
+    unlet! s:popup_table
+endfunction
+
+
+
+"=============================================
+" 				Query History	
+"=============================================
+" Shows the list of recently ran queries.
+" Selecting a query will re-run it.
+
+" View query history
+function! dbtables#OpenQueryHistory()
+    " Open the query history in a new split window
+    execute 'vsplit'
+    enew
+    call setline(1, s:query_history)
+    nnoremap <buffer> <CR> :call s:OpenInNewTab('SQLQueryResult', 
+				\ s:ExecuteDBQuery(getline(line('.'))))<CR>
+    setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile wrap
+endfunction
+
+
+
+"=============================================
+" 				Query Snippets	
+"=============================================
+" Shows the list of pre-set query snippets.
+" Selecting a snippet will open it in a new 
+" tab to be executed or modified.
+
+" View query snippets 
+function! dbtables#OpenQuerySnippets()
+    " Open the query snippets in a new split window
+    execute '34 vsplit'
+    enew
+
+	" Populate the buffer with the list of snippet files
+	let s:snippets = globpath(g:snippets_directory, '*', 0, 1)
+	let l:display = mapnew(s:snippets, 'fnamemodify(v:val, ":t:r")')
+	call setline(1, l:display)
+	
+	nnoremap <buffer> <CR> :call s:OpenInNewTab(line('.'),
+				\ fnameescape(s:snippets[a:lnum-1]))<CR>
+
+    setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile wrap
+endfunction
+
+
+
+"=============================================
+" 				DB Console	
+"=============================================
+" Opens a console to interact with the DB. 
+
+" Open MariaDB console
+function! dbtables#DBConsole()
+    " Save the current cursor position
+    let save_cursor = getpos(".")
+    let command = printf('mariadb --user=%s --password=%s --database=%s --host=%s',
+                  \ g:db_user, g:db_password,
+                  \ g:db_name, g:db_host)
+    
+    let command =  substitute(command, '\n', '', 'g')
+    execute ':term ' . command
+    call setpos(".", save_cursor)
+endfunction
--- a/doc/dbtables.txt	Tue Mar 10 20:25:15 2026 -0400
+++ b/doc/dbtables.txt	Wed Mar 11 08:53:55 2026 -0400
@@ -1,22 +1,169 @@
-*dbtables.txt*    Simple example Vim plugin
+*dbtables.txt*   Database interaction in Vim
 
 INTRODUCTION                                        *dbtables*
 
-dbtables is a minimal example plugin.
+dbtables is a small plugin to interact with a database from Vim:
+- Browse tables in a dedicated window
+- Execute SQL from the current buffer (normal and visual mode)
+- Open a DB console
+- Manage query history and snippets
+
+It is intended as a lightweight helper for SQL work inside Vim.
+
+INSTALLATION                                       *dbtables-install*
+
+Using vim-plug, add the following to your vimrc/init.vim:
+
+    Plug '/home/lsitas/repos/vim_plugins/dbtables'
+
+Then run:
+
+    :PlugInstall
 
 USAGE                                              *dbtables-usage*
 
-    :DbtablesGreet
-        Echo a greeting message. You can customize it with
-        g:dbtables_greeting:
+The plugin defines the following user commands and mappings.
+
+COMMANDS                                           *dbtables-commands*
+
+                                                    *:DBTables*
+:DBTables
+    Open the database tables window. Selecting a table can show
+	the schema of the table or all the data in the table.
+
+                                                    *:DBConsole*
+:DBConsole
+    Opens a console for interacting with the database. 
+
+                                                    *:ExecuteSQL*
+:ExecuteSQL
+    Execute the SQL query from the current buffer. If there are
+	query parameters included, the user will be prompted to 
+	fill them in. 
+	
+	Example:
+	"""
+	SELECT
+		id,
+		name
+	FROM 
+		my_table
+	WHERE 
+		id > :min_id;
+	"""
+	
+	The user will be prompted for a value for `min_id`
 
-        >   let g:dbtables_greeting = 'Hi there!'
+                                                    *:QueryHistory*
+:QueryHistory
+	Opens the list of recently ran queries. Selecting a query will
+	re-run the query. All parameters are already filled in.
+
+                                                    *:QuerySnippets*
+:QuerySnippets
+	Opens the list of saved query snippets. Selecting a snippet will
+	open the snippet in a new tab for modification or execution.
+
+MAPPINGS                                           *dbtables-mappings*
+
+All mappings use the <Leader> key in normal or visual mode.
+
+In NORMAL mode:
+
+    <Leader>dt
+        Same as |:DBTables|. Open the database tables window.
+
+    <Leader>eq
+        Same as |:ExecuteSQL|. Execute SQL from the current buffer.
+
+    <Leader>db
+        Same as |:DBConsole|. Open an interactive DB console.
+
+    <Leader>qh
+        Same as |:QueryHistory|. Open the query history list.
+
+    <Leader>qs
+        Same as |:QuerySnippets|. Open the query snippets list.
+
+In VISUAL mode:
+
+    <Leader>ev
+        Call dbtables#ExecuteVisualSQLQuery(). Execute only the
+        visually selected SQL text.
+
+CONFIGURATION                                      *dbtables-config*
 
-INSTALLATION                                       *dbtables-install*
+The plugin exposes several global variables you can set in your
+vimrc/init.vim before the plugin is loaded. Each has a default value
+if you do not define it.
+
+                                                    *g:snippets_directory*
+g:snippets_directory
+    Directory where query snippets are stored and loaded from.
+
+    Default:
+        $HOME/.config/heidisql/Snippets
+
+    Example:
+
+        let g:snippets_directory = expand('~/.vim/db_snippets')
+
+                                                    *g:db_user*
+g:db_user
+    Database username used by the plugin when connecting or running
+    queries.
+
+    Default:
+        ''  (empty string; you must set this to actually connect)
+
+    Example:
+
+        let g:db_user = 'myuser'
+
+                                                    *g:db_password*
+g:db_password
+    Database password associated with |g:db_user|.
+
+    Default:
+        ''  (empty string; set this if your DB requires a password)
+
+    Example:
 
-Using vim-plug add the following:
+        let g:db_password = 'mypassword'
+
+                                                    *g:db_name*
+g:db_name
+    Default database/schema name to connect to.
+
+    Default:
+        ''  (empty string; set this to the DB you want to use)
+
+    Example:
+
+        let g:db_name = 'mydatabase'
+
+                                                    *g:db_host*
+g:db_host
+    Hostname or IP address of the database server.
 
-Plug '/home/lsitas/repos/vim_plugins/dbtables'
+    Default:
+        ''  (empty string; set this to your DB host, e.g. 'localhost')
+
+    Example:
+
+        let g:db_host = 'localhost'
+
+NOTES                                              *dbtables-notes*
 
+- All mappings are defined in the plugin by default. If you prefer
+  your own keybindings, you can `:nunmap` or `:xunmap` them and
+  create custom mappings to the same functions
+  (e.g. dbtables#ExecuteSQLQuery()).
+
+- This help file documents only the public interface (commands,
+  mappings, and configuration variables). The internal functions
+  under the dbtables# namespace are intended to be called by these
+  interfaces, but you may also call them directly if you know what
+  you are doing.
 
 *dbtables*      Main help entry for this plugin.
--- a/plugin/dbtables.vim	Tue Mar 10 20:25:15 2026 -0400
+++ b/plugin/dbtables.vim	Wed Mar 11 08:53:55 2026 -0400
@@ -6,10 +6,31 @@
 endif
 let g:loaded_dbtables = 1
 
-" Default configuration option
-if !exists('g:dbtables_greeting')
-  let g:dbtables_greeting = 'Hello from dbtables!'
-endif
+" Config default values
+let g:snippets_directory = get(g:, 'snippets_directory',
+      \ expand('$HOME/.config/heidisql/Snippets'))
+let g:db_user          = get(g:, 'db_user',          '')
+let g:db_password      = get(g:, 'db_password',      '')
+let g:db_name          = get(g:, 'db_name',          '')
+let g:db_host          = get(g:, 'db_host',          '')
+
+"=============================================
+" 				Key Bindings	
+"=============================================
 
-" Command that calls an autoloaded function
-command! DbtablesGreet call dbtables#greet()
+" Keybinding to open query history
+command! DBTables call dbtables#OpenDBTablesWindow()
+command! DBConsole call dbtables#DBConsole()
+command! ExecuteSQL call dbtables#ExecuteSQLQuery()
+command! QueryHistory call dbtables#OpenQueryHistory()
+command! QuerySnippets call dbtables#OpenQuerySnippets()
+
+" Function to open the database tables window
+nnoremap <Leader>dt :DBTables<CR>
+
+nnoremap <Leader>eq :ExecuteSQL<CR>
+xnoremap <silent> <Leader>ev :call dbtables#ExecuteVisualSQLQuery()<CR>
+
+nnoremap <Leader>db :call DBConsole<CR>
+nnoremap <Leader>qh :call QueryHistory<CR>
+nnoremap <Leader>qs :call QuerySnippets<CR>