]> git.decadent.org.uk Git - ion3.git/blobdiff - mod_query/mod_query.lua
Imported Upstream version 20090110
[ion3.git] / mod_query / mod_query.lua
index 243f98785fafc317097fc52506531214f55c29f3..bd3414bd95764cd5c6d62147d9181e4af0e44d18 100644 (file)
@@ -1,12 +1,9 @@
 --
 -- ion/query/mod_query.lua -- Some common queries for Ion
 -- 
--- Copyright (c) Tuomo Valkonen 2004-2007.
+-- Copyright (c) Tuomo Valkonen 2004-2009.
 -- 
--- Ion is free software; you can redistribute it and/or modify it under
--- the terms of the GNU Lesser General Public License as published by
--- the Free Software Foundation; either version 2.1 of the License, or
--- (at your option) any later version.
+-- See the included file LICENSE for details.
 --
 
 
@@ -31,6 +28,20 @@ local DIE_TIMEOUT_NO_ERRORCODE=2 -- 2 seconds
 -- Generic helper functions {{{
 
 
+--DOC
+-- Display an error message box in the multiplexer \var{mplex}.
+function mod_query.warn(mplex, str)
+    ioncore.unsqueeze(mod_query.do_warn(mplex, str))
+end
+
+
+--DOC
+-- Display a message in \var{mplex}.
+function mod_query.message(mplex, str)
+    ioncore.unsqueeze(mod_query.do_message(mplex, str))
+end
+
+
 --DOC
 -- Low-level query routine. \var{mplex} is the \type{WMPlex} to display
 -- the query in, \var{prompt} the prompt string, and \var{initvalue}
@@ -50,19 +61,28 @@ function mod_query.query(mplex, prompt, initvalue, handler, completor,
     local function cycle(wedln)
         wedln:complete('next', 'normal')
     end
+    local function bcycle(wedln)
+        wedln:complete('prev', 'normal')
+    end
 
-    -- Check that no other queries are open in the mplex.
-    local ok=mplex:managed_i(function(r) 
-                                 return not obj_is(r, "WEdln") 
+    -- Check that no other queries or message boxes are open in the mplex.
+    local ok=mplex:managed_i(function(r)
+                                 return not (obj_is(r, "WEdln") or
+                                             obj_is(r, "WMessage"))
                              end)
     if not ok then
         return
     end
     
     local wedln=mod_query.do_query(mplex, prompt, initvalue, 
-                                   handle_it, completor, cycle)
-    if context then
-        wedln:set_context(context)
+                                   handle_it, completor, cycle, bcycle)
+                                   
+    if wedln then
+        ioncore.unsqueeze(wedln)
+        
+        if context then
+            wedln:set_context(context)
+        end
     end
     
     return wedln
@@ -219,13 +239,14 @@ mod_query.COLLECT_THRESHOLD=2000
 --DOC
 -- This function can be used to read completions from an external source.
 -- The parameter \var{cp} is the completion proxy to be used,
--- and the string \var{cmd} the shell command to be executed. To its stdout, 
--- the command should on the first line write the \var{common_beg} 
+-- and the string \var{cmd} the shell command to be executed, in the directory
+-- \var{wd}. 
+-- To its stdout, the command should on the first line write the \var{common_beg}
 -- parameter of \fnref{WComplProxy.set_completions} (which \var{fn} maybe used
 -- to override) and a single actual completion on each of the successive lines.
 -- The function \var{reshnd} may be used to override a result table
 -- building routine.
-function mod_query.popen_completions(cp, cmd, fn, reshnd)
+function mod_query.popen_completions(cp, cmd, fn, reshnd, wd)
     
     local pst={cp=cp, maybe_stalled=0}
     
@@ -298,12 +319,14 @@ function mod_query.popen_completions(cp, cmd, fn, reshnd)
     
     if not found_clean then
         pipes[rcv]=pst
-        ioncore.popen_bgread(cmd, coroutine.wrap(rcv))
+        ioncore.popen_bgread(cmd, coroutine.wrap(rcv), nil, wd)
     end
 end
 
 
 local function mk_completion_test(str, sub_ok, casei_ok)
+    local settings=mod_query.get()
+    
     if not str then
         return function(s) return true end
     end
@@ -317,9 +340,10 @@ local function mk_completion_test(str, sub_ok, casei_ok)
         end
     end
     
-    local casei=(casei_ok and mod_query.get().caseicompl)
+    casei_ok=(casei_ok and settings.caseicompl)
+    sub_ok=(sub_ok and settings.substrcompl)
     
-    if not casei then
+    if not casei_ok then
         return mk(str, sub_ok)
     else
         local fn=mk(string.lower(str), sub_ok)
@@ -437,24 +461,12 @@ function mod_query.attachclient_handler(frame, str)
         return
     end
     
-    local reg=cwin:manager()
-    local attach
+    local reg=cwin:groupleader_of()
     
-    if not obj_is(reg, "WGroupCW") then
-        reg = cwin
-        attach = function()
-                     frame:attach_new {
-                         type = "WGroupCW", 
-                         switchto = true,
-                         managed = {{ reg = cwin, bottom = true }}
-                     }
-                 end
-    else
-        attach = function()
-                     frame:attach(reg, { switchto = true })
-                 end
+    local function attach()
+        frame:attach(reg, { switchto = true })
     end
-        
+    
     if frame:rootwin_of()~=reg:rootwin_of() then
         mod_query.warn(frame, TR("Cannot attach: different root windows."))
     elseif reg:manager()==frame then
@@ -481,7 +493,10 @@ function mod_query.workspace_handler(mplex, name)
                 local scr=mplex:screen_of()
                 
                 local function mkws()
-                    local tmpl={name=name, switchto=true}
+                    local tmpl={
+                        name=(name~="" and name),
+                        switchto=true
+                    } 
                     if not ioncore.create_ws(scr, tmpl, layout) then
                         error(TR("Unknown error"))
                     end
@@ -504,9 +519,9 @@ end
 
 
 --DOC
--- This query asks for the name of a client window and attaches
--- it to the frame the query was opened in. It uses the completion
--- function \fnref{ioncore.complete_clientwin}.
+-- This query asks for the name of a client window and switches
+-- focus to the one entered. It uses the completion function
+-- \fnref{ioncore.complete_clientwin}.
 function mod_query.query_gotoclient(mplex)
     mod_query.query(mplex, TR("Go to window:"), nil,
                     mod_query.gotoclient_handler,
@@ -515,9 +530,9 @@ function mod_query.query_gotoclient(mplex)
 end
 
 --DOC
--- This query asks for the name of a client window and switches
--- focus to the one entered. It uses the completion function
--- \fnref{ioncore.complete_clientwin}.
+-- This query asks for the name of a client window and attaches
+-- it to the frame the query was opened in. It uses the completion
+-- function \fnref{ioncore.complete_clientwin}.
 function mod_query.query_attachclient(mplex)
     mod_query.query(mplex, TR("Attach window:"), nil,
                     mod_query.attachclient_handler, 
@@ -736,7 +751,7 @@ local function find_point(strs, point)
 end
 
 
-function mod_query.exec_completor(wedln, str, point)
+function mod_query.exec_completor_(wd, wedln, str, point)
     local parts=break_cmdline(str)
     local complidx=find_point(parts, point+1)
     
@@ -794,11 +809,16 @@ function mod_query.exec_completor(wedln, str, point)
     if ic then
         mod_query.popen_completions(wedln,
                                    ic..wp..string.shell_safe(s_compl),
-                                   set_fn, filter_fn)
+                                   set_fn, filter_fn, wd)
     end
 end
 
 
+function mod_query.exec_completor(...)
+    mod_query.exec_completor_(nil, ...)
+end
+
+
 local cmd_overrides={}
 
 
@@ -828,9 +848,12 @@ end
 -- \file{ion-runinxterm}. Two colons ('::') will ask you to press 
 -- enter after the command has finished.
 function mod_query.query_exec(mplex)
-    mod_query.query(mplex, TR("Run:"), nil, mod_query.exec_handler, 
-                    mod_query.exec_completor,
-                    "run")
+    local function compl(...)
+        local wd=ioncore.get_dir_for(mplex)
+        mod_query.exec_completor_(wd, ...)
+    end
+    mod_query.query(mplex, TR("Run:"), nil, mod_query.exec_handler,
+                    compl, "run")
 end
 
 
@@ -888,7 +911,7 @@ function mod_query.get_hostnicks(mplex)
                 patterns=pat
             elseif string.find(substr, "^[nN][aA][mM][eE]")
                 and patterns then
-                for s in string.gfind(patterns, "%S+") do
+                for s in string.gmatch(patterns, "%S+") do
                     if not string.find(s, "[*?]") then
                         table.insert(mod_query.hostnicks, s)
                     end
@@ -912,7 +935,7 @@ function mod_query.complete_ssh(str)
     end
     
     local res = {}
-    local tst = mk_completion_test(host, true, false)
+    local tst = mk_completion_test(host, true, true)
     
     for _, v in ipairs(mod_query.ssh_completions) do
         if tst(v) then
@@ -961,8 +984,10 @@ end
 
 function mod_query.man_completor(wedln, str)
     local mc=ioncore.lookup_script("ion-completeman")
+    local icase=(mod_query.get().caseicompl and " -icase" or "")
+    local mid=""
     if mc then
-        mod_query.popen_completions(wedln, (mc.." -complete "
+        mod_query.popen_completions(wedln, (mc..icase..mid.." -complete "
                                             ..string.shell_safe(str)))
     end
 end
@@ -1003,6 +1028,7 @@ function mod_query.do_handle_lua(mplex, env, code)
     local print_res
     local function collect_print(...)
         local tmp=""
+        local arg={...}
         local l=#arg
         for i=1,l do
             tmp=tmp..tostring(arg[i])..(i==l and "\n" or "\t")
@@ -1044,7 +1070,7 @@ function mod_query.do_complete_lua(env, str)
     
     -- Descend into tables
     if tocomp and string.len(tocomp)>=1 then
-        for t in string.gfind(tocomp, "([^.:]*)[.:]") do
+        for t in string.gmatch(tocomp, "([^.:]*)[.:]") do
             metas=false
             if string.len(t)==0 then
                 comptab=env;
@@ -1132,9 +1158,15 @@ end
 
 --DOC
 -- This query can be used to create a query of a defined menu.
-function mod_query.query_menu(mplex, themenu, prompt)
-    local _sub=mplex:current()
-    local menu=ioncore.evalmenu(themenu, {mplex, _sub})
+function mod_query.query_menu(mplex, sub, themenu, prompt)
+    if type(sub)=="string" then
+        -- Backwards compat. shift
+        prompt=themenu
+        themenu=sub
+        sub=nil
+    end
+    
+    local menu=ioncore.evalmenu(themenu, mplex, sub)
     local menuname=(type(themenu)=="string" and themenu or "?")
     
     if not menu then
@@ -1149,19 +1181,25 @@ function mod_query.query_menu(mplex, themenu, prompt)
     end
 
     local function xform_name(n, is_submenu)
-        return (string.lower(string.gsub(n, "[-/%s]+", "-"))
-                ..(is_submenu and "/" or ""))
+        return string.lower(string.gsub(n, "[-/%s]+", "-"))
     end
 
     local function xform_menu(t, m, p)
         for _, v in ipairs(m) do
             if v.name then
                 local is_submenu=v.submenu_fn
-                local n=p..xform_name(v.name, is_submenu)
-                while t[n] do
+                local n=p..xform_name(v.name)
+                
+                while t[n] or t[n..'/'] do
                     n=n.."'"
                 end
+                
+                if is_submenu then
+                    n=n..'/'
+                end
+                
                 t[n]=v
+                
                 if is_submenu and not v.noautoexpand then
                     local sm=v.submenu_fn()
                     if sm then
@@ -1179,8 +1217,7 @@ function mod_query.query_menu(mplex, themenu, prompt)
     local ntab=xform_menu({}, menu, "")
     
     local function complete(str)
-        -- casei_ok false, because everything is already in lower case
-        return mod_query.complete_keys(ntab, str, true, false)
+        return mod_query.complete_keys(ntab, str, true, true)
     end
     
     local function handle(mplex, str)