Replies: 5 comments 16 replies
-
Mostly as an illustration of the difficulties here's an update on the above effort. It's got not-quite-working sql completion or not-quite-working latched sql mode but not both together :) It does seem like ble.sh could usefully expand into adjacent readline-using territory pretty easily but more knowledge of it's innards than I've got would be decidedly useful. sqliteServerDBFile=
function sqliteServerUpdateCompletionWords {
[ -n "$sqliteServerDBFile" ] || return 1
[ -r "$sqliteServerDBFile" ] || return 2
# FIXME: unfortunately neither bash nor blesh let this work on anything
# other than a word at the very start of a single-quoted string or HERE doc
# :( I guess some complete -F or something on ble.sh side would be needed
complete -r sl 2>/dev/null
complete \
-W "$(~/.helper_scripts/sqlite3_db_completion_words $sqliteServerDBFile)" \
sl
}
sqliteServerMagicMarker='sqliteServerMAaaaaGiiICMarker'
sqliteServerMarkerPrinter=".print $sqliteServerMagicMarker"
function startSqliteServerCoproc {
coproc sqliteServer { sqlite3 -interactive $@; }
# WARNING: comment these out again to get better notice what's up with
# coprocesses (but then C-q etc. don't work as usual anymore)
disown $sqliteServer_PID
# Get and pass greeting lines from sqlite3 through to reassure user
local reply_line
read -r reply_line <&"${sqliteServer[0]}"
echo $reply_line
read -r reply_line <&"${sqliteServer[0]}"
echo $reply_line
# The first non-option argument must be the db file
local dbf=
for arg in $@; do
if [[ $arg =~ ^[^-] ]]; then
sqliteServerDBFile=$arg
fi
done
sqliteServerUpdateCompletionWords || return 1;
}
function sendToSqliteServer {
local awn=${@//$'\n'/} # Args Without Newlines
local maybe_sc=
# Don't automatically semicolonize .directive commands
if [[ ! $awn =~ ^\. ]]; then
maybe_sc=';'
fi
{
echo "$awn $maybe_sc";
echo "$sqliteServerMarkerPrinter";
} >&"${sqliteServer[1]}";
}
function readFromSqliteServer {
local reply_line
read -r reply_line <&"${sqliteServer[0]}"
[[ $reply_line =~ ^sqlite\> ]] || return 1 # Eat prompt and echoed command
while true; do
read -r reply_line <&"${sqliteServer[0]}"
[ "$reply_line" == "sqlite> $sqliteServerMarkerPrinter" ] && break
echo "$reply_line"
done
while true; do
read -r reply_line <&"${sqliteServer[0]}"
[[ $reply_line =~ ^$sqliteServerMagicMarker ]] && break
done
}
function sl {
# This is the function to use to enter queries on the command line
sendToSqliteServer "$@" && readFromSqliteServer
sqliteServerUpdateCompletionWords
} where the completion word probe script #!/usr/bin/perl -w
# Given an sqlite3 db file, probe it with some sqlite3 commands to determine
# a set of completion words of interest associated with it (table and column
# names) and output that list of words one per line on STDOUT.
#
# The shipping sqlite3 client doesn't seem to consider context at all when
# completing but just lumps all table names and column names (but strangely
# not all virtual table column names) together in a single pool. If the
# table and column names are sane this works well enough and that's what
# this script is intended to support for contexts other than the sqlite3
# client (excep we also get virtual table column names :).
# vim:foldmethod=marker
# Pragmas and Modules # {{{1
use strict;
use strictures;
use v5.30;
use feature 'signatures';
no warnings qw(experimental::signatures);
use Carp;
use Data::Dumper;
# }}}1
sub sysck ($cmd) # {{{1
{
# Like system() but the error check is integrated
not system($cmd) or confess "command '$cmd' returned non-zero";
} # }}}1
sub btck ($cmd) # {{{1
{
# Like backticks but the error check and chomp() are integrated
my $result = `$cmd`;
$? == 0 or confess "backtick command '$cmd' returned non-zero";
chomp($result);
return $result;
} # }}}1
@ARGV == 1 or die "wrong number of arguments";
my $dbf = $ARGV[0]; # DataBase File
sub dbc ($cmd) # {{{1
{
# DataBase Command
my $po = btck("sqlite3 -line $dbf '$cmd' 2>&1"); # Probe Output
# The chomp in out btck() might have removed the \n here so we only remove it
# if it's present and don't complain if it isn't:
$po =~ s/^-- Loading resources from .*\n?// or confess "$po";
return $po;
} # }}}1
sub tables () # Ref to list of tables/views/(and indexes/triggers also?) {{{1
{
my $co = dbc('.tables'); # Command Output
$co =~ s/\s+/ /g;
return [ split(' ', $co) ]
} # }}}1
sub columns ($table) # Ref to column names of given table/view) {{{1
{
my $co = dbc("PRAGMA table_info($table)");
my @rw = map { m/^\s*name\s*=\s*(\w+)\s*$/ ? $1 : () } split("\n", $co);
return \@rw;
} # }}}1
my @tables = @{tables()};
my @columns = map { @{columns($_)} } @tables;
my @sorted_unique_words = sort keys %{{map { $_ => 1 } (@tables, @columns)}};
print join("\n", @sorted_unique_words)."\n"; And the latching mode: # If defined non-empty commands should go to the sqlite coproc
sqliteMode=
function esm { sqliteMode=defined_nonempty; } # Enter sqliteMode
function lsm { sqliteMode=; } # Leave sqliteMode
function my/maybeSetPromptForSqliteMode.hook {
if [ -n "$sqliteMode" ]; then
PS1='mySqlite> '
else
PS1='$ '
fi
}
blehook PRECMD=my/maybeSetPromptForSqliteMode.hook
# FIXME: this is pretty pathological in general, and unfinished. For example
# double quotes presumably don't make it through to sqlite correctly,
# complete currently doesn't work because no leading sl (I think we could
# just nuke all completions and replace with a new command-independent
# set consisting of just the ones currently used for sl command) 'select'
# is a bash keyword that by itself kicks off multi-line mode in ble.sh
# (which is sort of convenient :) but SELECT isn't (though with the newline
# replacement here multi-line mode can be forced with a string literal with
# only a newline), etc. Modifying _ble_edit_exe_BASH_COMMAND_eval looks
# pretty unsuppored and risky. ble/widget/vi_imap/accept-single-line-or
# (and similar stuff for vi_nmap) could be changed to make multi-line mode
# the default, and maybe intelligently terminate if a trailing semicolon is
# found (though really probably better to just require C-j as elsewhere in
# ble.sh) I think a wide swath of ble.sh would need to be rewired to make
# this work well.
function my/maybeChangeCommandToSendToSqliteServer.hook {
if [ -n "$sqliteMode" ]; then
local ibc="$_ble_edit_exec_BASH_COMMAND_eval"; # Impending "BASH_COMMAND"
ibc="${ibc//$'\n'/ }" # Replace newlines with spaces
local space=$' \t'
local rex='^['${space}']*lsm['${space}']*$'
if [[ $ibc =~ $rex ]]; then
sqliteMode=
return 0
fi
_ble_edit_exec_BASH_COMMAND_eval='sl '"\"$ibc\""
fi
}
blehook PREEXEC=my/maybeChangeCommandToSendToSqliteServer.hook |
Beta Was this translation helpful? Give feedback.
-
Regarding completion yes it's the single-quote version (and HERE docs) that don't work as is. I think these must work as the additional load of thinking about shell metachars is too much (at least for me) while considering sql query. I'll try with complete -F later. Regarding prefix (e.g. + or sl) I now think you're right it's the way to go here (versus e.g. latched sqlite mode). Latched mode is just a habit from the existing client and the first thing one wants to do with better integration is to e.g. pipe to grep (in theory possible from db side of course but for whatever reason it often seems simpler when investigating to use an after-the-fact filter). The prefix sl is not much to type or remember, is all up-front, and is often present in history during the refining process anyway. I expect most of this is true of gnuplot and probably most other REPL with commands complicated enough to be use cases here. Regarding pipes I couldn't figure out how to get them to work with bash coproc because it closes the pipe ends in children. So I've now tried the util.bgproc you made and it works nicely :) The only issue is for some reason it seems to make the final exit from a ble.sh shell quite a lot slower. If there's some way to tell bgproc to die faster I didn't find it. One other note on a different topic: I didn't know about the nice comments in e.g. util.bgproc because I just looked at installed sources where they're apparently compiled out for speed. As looking at/instrumenting installed scripts is a pretty common way to start with devel for scripts it might be worth compiling in a header comment directing user to original sources, or maybe even a mode to include commented version for easy reading while instrumenting in-place (unfortunately I can't read the Japanese so it might not help me much but maybe others :) |
Beta Was this translation helpful? Give feedback.
-
Carrying on I set out to make completion work inside HERE doc in this:
This finally has the desired properties that it's immune to bash syntax and can be used in pipelines etc. Unfortunately it looks like complete -F functions don't run at all inside HERE documents. I guess this isn't too shocking. So I wondered how to work around |
Beta Was this translation helpful? Give feedback.
-
In https://github.com/bkerin/ble.sh are changes to lib/core-complete.sh that allow completion of sqlite3 meta-commands/tables/columns inside the HERE doc to work (together with functions from my .bashrc). It's a bit of a hack and I haven't come close to understanding all of core-complete.sh, but I have the following theories in which I have varying degrees of confidence:
So I've found a place to splice in custom completion before any of the ble.sh syntax pass happens. Based on past conversations I guess there are probably other places where ble.sh doesn't fully parse and these are likely to be the ones where full context-sensitive completion might be desired. It does seem a shame to invite users to make their own poor reinventions of the sophisticated command detection/expansion/etc. that are already happening in core-complete.sh, but that stuff is pretty hard to fully learn and in Remaining issues: it would be nice if when an sl command is loaded from history the cursor could be positioned at the point it was when C-j got pushed. Maybe there's already some way to do this though. |
Beta Was this translation helpful? Give feedback.
-
Ok I'll try this later.
I wouldn't expect any parsing inside HERE of course, but at the moment ble/complete/context:syntax/generate-sources
I agree that trying to sneakily extend the bash completion setup isn't a good idea, but it seems like ble.sh could support something more powerful (and appropriate to it's stronger multi-line handling at about the same site? But as things are completion doesn't get that far.
I'm not sure, but in this setup I'm attempting where slave processes are used to allow ble.sh superior vim keys and multiline support it seems like a logical thing to want, since the topic of refinement is likely to be the material in the contained HERE document. And in general the good multi-line support invites users to use formatting and do more at the prompt before going to files, and doing that makes maintaining cursor position desirable. IIRC there's already a hook to rewrite history as it occurs, so this could be achieved only by interested users if there was a retrieval-time hook as well (and ideally a documented way to set the cursor position).
I took a look but it's not obvious to me what single-command-mode is doing |
Beta Was this translation helpful? Give feedback.
-
I tried again with your advice on building bash with multiple coproc and it worked :). So I though maybe it might be time to get rid of readline everywhere, or at least everywhere I spend a lot of time. So here is a start at this for sqlite3:
It works nicely now can say e.g.:
Next would be some sort of latching mode or at least a binding type thingy for
sl
at start of line that types the''
for me :)Beta Was this translation helpful? Give feedback.
All reactions