Commits

Tamas Kovacs  committed acf489d

Version 0.8.4

Added handling for Unicode characters, truncate arglist output to fit in the status line, added debugger keybindings: ,a for abort ,q for quit ,n for continue, changed keybinding for apropos to ,A, added compiler error messages to quickfix list, map insert mode <Space> and <Tab> only for lisp (and dialects) buffers, bugfixes: wait for the response to :create-repl before calling :swank-require (thanks to Philipp Marek), indentation problems with unbalanced parens in comment, arglist ate the <Space> when virtualedit was off.

  • Participants
  • Parent commits 91354b5

Comments (0)

Files changed (9)

 
 Slimv opens the lisp REPL (Read-Eval-Print Loop) inside a Vim buffer. Lisp commands may be entered and executed in the REPL buffer, just as in a regular REPL.
 
-Slimv supports SLIME's debugger, profiler, cross reference, symbol name completion functions. The script also has a Common Lisp Hyperspec lookup feature and it is able to lookup symbols in the Clojure API, as well as in JavaDoc.
+Slimv supports SLIME's debugger, profiler, cross reference, arglist, indentation, symbol name completion functions. The script also has a Common Lisp Hyperspec lookup feature and it is able to lookup symbols in the Clojure API, as well as in JavaDoc.
 
 Slimv comes with Paredit Mode, which is similar to the functionality of paredit.el in Emacs. Paredit Mode tries to maintain the balanced state of matched characters (parenthesis marks, square brackets, double quotes). Matched characters are inserted and removed in pairs, also when working with a block of text (well, mostly). Slimv also implements many paredit.el s-expression handling functions, like Split/Join/Wrap/Splice. Slurpage and Barfage known from Emacs is also possible but in a different fashion: you don't move the list element in or out of the list, rather you move the opening or closing parenthesis over the element or sub-list.
 
 Edit commands:
     *  Close Form
     *  Complete Symbol
+    *  Function Arglist
     *  Paredit Toggle
 
 Evaluation commands:
     *  Untrace All
     *  Disassemble
     *  Inspect
+    *  Abort
+    *  Quit to Toplevel
+    *  Continue
 
 Compile commands:
     *  Compile Defun
 
 Profile commands:
     *  Toggle Profile
-    *  Profile By Substring
+    *  Profile by Substring
     *  Unprofile All
     *  Show Profiled
     *  Profile Report

File doc/slimv.txt

-*slimv.txt*                    Slimv                 Last Change: 17 May 2011
+*slimv.txt*                    Slimv                 Last Change: 16 Jun 2011
 
 Slimv                                                                  *slimv*
-                               Version 0.8.3
+                               Version 0.8.4
 
 The Superior Lisp Interaction Mode for Vim.
 This plugin is aimed to help Lisp development by interfacing between Vim and
     ---------------------------------------------------
     ,,      ,,       Slimv Menu
 
-    Edit commands:
-    <C-X>0           Close-Form (Insert mode)
-    <C-X><C-O>       Complete-Symbol (Insert mode)
+    Edit commands (Insert mode):
+    <C-X>0           Close Form
+    <Tab>            Complete Symbol
+    <Space>          Function Arglist (only when using SWANK client)
+
+    Edit commands (Normal mode):
+    ,)      ,tc      Close Form
     ,(      ,(t      Paredit Toggle
 
     Evaluation commands:
     ,d      ,ed      Eval Defun (current top level form)
     ,e      ,ee      Eval Current Expression (current subform)
-    ,E      ,ep      Pprint Eval Current Expression
     ,r      ,er      Eval Region (visual selection)
     ,b      ,eb      Eval Buffer
     ,v      ,ei      Interactive Eval
     Debug commands:
     ,1      ,m1      Macroexpand-1
     ,m      ,ma      Macroexpand All
-    ,t      ,dt      Trace
-    ,T      ,du      Untrace
+    ,t      ,dt      Toggle Trace
+    ,T      ,du      Untrace All
     ,l      ,dd      Disassemble
     ,i      ,di      Inspect
+    ,a      ,da      Abort (only when using SWANK client)
+    ,q      ,dq      Quit to Toplevel (only when using SWANK client)
+    ,n      ,dc      Continue (only when using SWANK client)
 
     Compile commands:
     ,D      ,cd      Compile Defun
     ,F      ,cf      Compile File
     ,R      ,cr      Compile Region
 
+    Cross Reference commands (only when using SWANK client):
+    ,xc     ,xc      Who Calls
+    ,xr     ,xr      Who References
+    ,xs     ,xs      Who Sets
+    ,xb     ,xb      Who Binds
+    ,xm     ,xm      Who Macroexpands
+    ,xp     ,xp      Who Specializes
+    ,xl     ,xl      List Callers
+    ,xe     ,xe      List Callees
+
     Profile commands:
-    ,O      ,pl      Load Profiler
-    ,p      ,pp      Profile
-    ,P      ,pu      Unprofile
+    ,p      ,pp      Toggle Profile
+    ,B      ,pb      Profile by Substring
     ,U      ,pa      Unprofile All
     ,?      ,ps      Show Profiled
     ,o      ,pr      Profile Report
 
     Documentation commands:
     ,s      ,ds      Describe Symbol
-    ,a      ,da      Apropos
+    ,A      ,da      Apropos
     ,h      ,dh      Hyperspec
     ,]      ,dt      Generate Tags
 
 ===============================================================================
 CHANGE LOG                                                    *slimv-changelog*
 
+0.8.4  - Added handling for Unicode characters.
+       - Truncate arglist output to fit in the status line.
+       - Added debugger keybindings: ,a for abort ,q for quit ,n for continue.
+       - Changed keybinding for apropos to ,A
+       - Added compiler error messages to quickfix list.
+       - Map insert mode <Space> and <Tab> only for lisp (and dialects) buffers.
+       - Bugfix: wait for the response to :create-repl before calling
+         :swank-require (thanks to Philipp Marek).
+       - Bugfix: indentation problems with unbalanced parens in comment.
+       - Bugfix: arglist ate the <Space> when virtualedit was off.
+
 0.8.3  - Added top/bottom/left/right directions to g:slimv_repl_split.
        - Added :Lisp (and an equivalent :Eval) command with completion.
        - Added g:slimv_leader and g:paredit_leader options.

File doc/swank.txt

-*swank.txt*                    Slimv                 Last Change: 17 May 2011
+*swank.txt*                    Slimv                 Last Change: 16 Jun 2011
 
 SWANK client for Slimv                                    *swank* *slimv-swank*
                                Version 0.8.3
 |swank-trace|                Trace function
 |swank-profile|              Profiler
 |swank-xref|                 Cross Reference
+|swank-quickfix|             Compiler errors in quickfix list
 
 -------------------------------------------------------------------------------
 EVALUATION                                                         *swank-eval*
 
   If you press Enter in normal mode on a restart line then the given restart
   is invoked.
+  The most frequently used restarts have the following shortcuts defined:
+
+    ,a      Abort
+    ,q      Quit To Toplevel
+    ,n      Continue
 
 
 -------------------------------------------------------------------------------
 -------------------------------------------------------------------------------
 FUNCTION ARGUMENT LIST                                          *swank-arglist*
 
-  When entering an s-expressin in insert mode, each time a space is pressed
+  When entering an s-expression in insert mode, each time a space is pressed
   after a non-whitespace character, then SWANK is requested for the function
   argument list for the current function. If the function is known by SWANK
-  then the function prototype is displayed in the status line.
+  then the function prototype is displayed in the status line. The arglist is
+  condensed in order to fit the status line, so for functions with many
+  arguments the whole definition may not be visible. In this case use the
+  Describe function for displaying the full function definition.
 
   Note: the function argument list is not displayed when Slimv is not
   connected to the SWANK server.
   Please note that not all Lisp implementations support the xref functionality.
 
 
+-------------------------------------------------------------------------------
+QUICKFIX                                                       *swank-quickfix*
+
+  The compiler error messages are fed into Vim's quickfix list, as well as
+  printed in the REPL buffer. Enter the :cw command to open the quickfix window.
+  Use :cn and :cp to jump to the next and previous error location, use :cr to
+  rewind to the first error.
+  Consult |quickfix| for details on using the quickfix functionality.
+
+
 ===============================================================================
 FUNCTIONS                                                     *swank-functions*
 

File ftplugin/clojure/slimv-clojure.vim

 " slimv-clojure.vim:
 "               Clojure filetype plugin for Slimv
-" Version:      0.8.0
-" Last Change:  10 Apr 2011
+" Version:      0.8.4
+" Last Change:  28 May 2011
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 " =====================================================================
 "
 "  Load Once:
-if &cp || exists( 'g:slimv_clojure_loaded' )
+if exists("b:did_ftplugin")
     finish
 endif
 
+" ---------- Begin part loaded once ----------
+if !exists( 'g:slimv_clojure_loaded' )
+
 let g:slimv_clojure_loaded = 1
 
 " Transform filename so that it will not contain spaces
 endfunction
 
 " Source Slimv general part
-runtime ftplugin/**/lisp.vim
 runtime ftplugin/**/slimv.vim
 
+endif "!exists( 'g:slimv_lisp_loaded' )
+" ---------- End of part loaded once ----------
+
+runtime ftplugin/**/lisp.vim
+
+" Must be called for each lisp buffer
+call SlimvInitBuffer()
+
+" Don't load another plugin for this buffer
+let b:did_ftplugin = 1
+

File ftplugin/lisp/slimv-lisp.vim

 " slimv-lisp.vim:
 "               Lisp filetype plugin for Slimv
-" Version:      0.8.0
-" Last Change:  02 Apr 2011
+" Version:      0.8.4
+" Last Change:  28 May 2011
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 " =====================================================================
 "
 "  Load Once:
-if &cp || exists( 'g:slimv_lisp_loaded' )
+if exists("b:did_ftplugin")
     finish
 endif
 
+" ---------- Begin part loaded once ----------
+if !exists( 'g:slimv_lisp_loaded' )
+
 let g:slimv_lisp_loaded = 1
 
 " Try to autodetect Lisp executable
 " Source Slimv general part
 runtime ftplugin/**/slimv.vim
 
+endif "!exists( 'g:slimv_lisp_loaded' )
+" ---------- End of part loaded once ----------
+
+runtime ftplugin/**/lisp.vim
+
+" Must be called for each lisp buffer
+call SlimvInitBuffer()
+
+" Don't load another plugin for this buffer
+let b:did_ftplugin = 1
+

File ftplugin/scheme/slimv-scheme.vim

 " slimv-scheme.vim:
 "               Scheme filetype plugin for Slimv
-" Version:      0.8.2
-" Last Change:  27 Apr 2011
+" Version:      0.8.4
+" Last Change:  28 May 2011
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 " =====================================================================
 "
 "  Load Once:
-if &cp || exists( 'g:slimv_scheme_loaded' )
+if exists("b:did_ftplugin")
     finish
 endif
 
+" ---------- Begin part loaded once ----------
+if !exists( 'g:slimv_scheme_loaded' )
+
 let g:slimv_scheme_loaded = 1
 
 " Try to autodetect Scheme executable
 " Source Slimv general part
 runtime ftplugin/**/slimv.vim
 
+endif "!exists( 'g:slimv_lisp_loaded' )
+" ---------- End of part loaded once ----------
+
+runtime ftplugin/**/lisp.vim
+
+" Must be called for each lisp buffer
+call SlimvInitBuffer()
+
+" Don't load another plugin for this buffer
+let b:did_ftplugin = 1
+

File ftplugin/slimv.vim

 " slimv.vim:    The Superior Lisp Interaction Mode for VIM
-" Version:      0.8.3
-" Last Change:  17 May 2011
+" Version:      0.8.4
+" Last Change:  09 Jun 2011
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 " =====================================================================
 
 " Display an error message
-function SlimvError( msg )
+function! SlimvError( msg )
     echohl ErrorMsg
     echo a:msg
     echohl None
 endfunction 
 
 " Display an error message and a question, return user response
-function SlimvErrorAsk( msg, question )
+function! SlimvErrorAsk( msg, question )
     echohl ErrorMsg
     let answer = input( a:msg . a:question )
     echo ""
 endfunction 
 
 " Display an error message and wait for ENTER
-function SlimvErrorWait( msg )
+function! SlimvErrorWait( msg )
     call SlimvErrorAsk( a:msg, " Press ENTER to continue." )
 endfunction 
 
+" Shorten long messages to fit status line
+function! SlimvShortEcho( msg )
+    let saved=&shortmess
+    set shortmess+=T
+    exe "normal :echomsg a:msg\n"
+    let &shortmess=saved
+endfunction
+
 " Position the cursor at the end of the REPL buffer
 " Optionally mark this position in Vim mark 's'
 function! SlimvEndOfReplBuffer()
 endfunction
 
 " Find starting '(' of a top level form
-function SlimvFindDefunStart()
+function! SlimvFindDefunStart()
     let l = line( '.' )
     let matchb = max( [l-100, 1] )
     while searchpair( '(', '', ')', 'bW', s:skip_sc, matchb )
 " Find and add language specific package/namespace definition before the
 " cursor position and if exists then add it in front of the current selection
 function! SlimvFindPackage()
-    if !g:slimv_package || s:debug_activated || SlimvGetFiletype() == 'scheme'
+    if !g:slimv_package || SlimvGetFiletype() == 'scheme'
         return
     endif
     if SlimvGetFiletype() == 'clojure'
                 call SlimvSwankResponse()
             endwhile
             if s:swank_version >= '2008-12-23'
-                python swank_create_repl()
-                call SlimvSwankResponse()
+                call SlimvCommandGetResponse( ':create-repl', 'python swank_create_repl()' )
             endif
             let s:swank_connected = 1
             if g:slimv_simple_compl == 0
         return 0
     endif
     " Use custom indentation only if default indenting is >2
+    set lisp
     let li = lispindent(a:lnum)
+    set nolisp
     if li > 2
         " Find start of current form
         let [l, c] = searchpairpos( '(', '', ')', 'nbW', s:skip_sc, pnum )
     call SlimvRefreshReplBuffer()
 endfunction
 
+" Select a specific restart in debugger
+function! SlimvDebugCommand( cmd )
+    if g:slimv_swank
+        if s:swank_connected
+            if s:debug_activated
+                call SlimvCommand( 'python ' . a:cmd . '()' )
+                call SlimvRefreshReplBuffer()
+            else
+                call SlimvError( "Debugger is not activated." )
+            endif
+        else
+            call SlimvError( "Not connected to SWANK server." )
+        endif
+    endif
+endfunction
+
 " Display function argument list
 function! SlimvArglist()
     let l = line('.')
         setlocal iskeyword+=~,#,&,\|,{,},[,],!,?
     endif
     if s:swank_connected && c > 1 && line[c-2] =~ '\k'
+        let save_ve = &virtualedit
+        set virtualedit=onemore
         " Display only if entering the first space after a keyword
         let matchb = max( [l-100, 1] )
         let [l0, c0] = searchpairpos( '(', '', ')', 'nbW', s:skip_sc, matchb )
                     let s:save_showmode = &showmode
                     set noshowmode
                     let msg = substitute( msg, "\n", "", "g" )
+                    redraw
                     if match( msg, arg ) != 1
                         " Function name is not received from REPL
-                        echo "\r(" . arg . ' ' . msg[1:]
+                        call SlimvShortEcho( "(" . arg . ' ' . msg[1:] )
                     else
-                        echo "\r" . msg
+                        call SlimvShortEcho( msg )
                     endif
                 endif
             endif
         endif
+        let &virtualedit=save_ve
     endif
 
     " Return empty string because this function is called from an insert mode mapping
     endif
 endfunction
 
-if g:slimv_swank
-    " Map space to display function argument list in status line
-    inoremap <silent> <Space>    <Space><C-R>=SlimvArglist()<CR>
-    "noremap  <silent> <C-C>      :call SlimvInterrupt()<CR>
-    au InsertLeave * :let &showmode=s:save_showmode
-endif
+" Initialize buffer by adding buffer specific mappings
+function! SlimvInitBuffer()
+    if g:slimv_swank
+        " Map space to display function argument list in status line
+        inoremap <silent> <buffer> <Space>    <Space><C-R>=SlimvArglist()<CR>
+        "noremap  <silent> <buffer> <C-C>      :call SlimvInterrupt()<CR>
+        au InsertLeave * :let &showmode=s:save_showmode
+    endif
+    inoremap <silent> <buffer> <C-X>0     <C-O>:call SlimvCloseForm()<CR>
+    inoremap <silent> <buffer> <Tab>      <C-R>=pumvisible() ? "\<lt>C-N>" : "\<lt>C-X>\<lt>C-O>"<CR>
+endfunction
 
 " Edit commands
-inoremap <silent> <C-X>0     <C-O>:call SlimvCloseForm()<CR>
-inoremap <silent> <Tab>      <C-R>=pumvisible() ? "\<lt>C-N>" : "\<lt>C-X>\<lt>C-O>"<CR>
 call s:MenuMap( 'Slim&v.Edi&t.Close-&Form',                     g:slimv_leader.')',  g:slimv_leader.'tc',  ':<C-U>call SlimvCloseForm()<CR>' )
 call s:MenuMap( 'Slim&v.Edi&t.&Complete-Symbol<Tab>Tab',        '',                  '',                   '<Ins><C-X><C-O>' )
 call s:MenuMap( 'Slim&v.Edi&t.&Paredit-Toggle',                 g:slimv_leader.'(',  g:slimv_leader.'(t',  ':<C-U>call PareditToggle()<CR>' )
 
 call s:MenuMap( 'Slim&v.De&bugging.Disassemb&le\.\.\.',         g:slimv_leader.'l',  g:slimv_leader.'dd',  ':call SlimvDisassemble()<CR>' )
 call s:MenuMap( 'Slim&v.De&bugging.&Inspect\.\.\.',             g:slimv_leader.'i',  g:slimv_leader.'di',  ':call SlimvInspect()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Abort',                     g:slimv_leader.'a',  g:slimv_leader.'da',  ':call SlimvDebugCommand("swank_invoke_abort")<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Quit-to-Toplevel',          g:slimv_leader.'q',  g:slimv_leader.'dq',  ':call SlimvDebugCommand("swank_throw_toplevel")<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Continue',                  g:slimv_leader.'n',  g:slimv_leader.'dc',  ':call SlimvDebugCommand("swank_invoke_continue")<CR>' )
 
 " Compile commands
 call s:MenuMap( 'Slim&v.&Compilation.Compile-&Defun',           g:slimv_leader.'D',  g:slimv_leader.'cd',  ':<C-U>call SlimvCompileDefun()<CR>' )
 
 " Documentation commands
 call s:MenuMap( 'Slim&v.&Documentation.Describe-&Symbol',       g:slimv_leader.'s',  g:slimv_leader.'ds',  ':call SlimvDescribeSymbol()<CR>' )
-call s:MenuMap( 'Slim&v.&Documentation.&Apropos',               g:slimv_leader.'a',  g:slimv_leader.'da',  ':call SlimvApropos()<CR>' )
+call s:MenuMap( 'Slim&v.&Documentation.&Apropos',               g:slimv_leader.'A',  g:slimv_leader.'dp',  ':call SlimvApropos()<CR>' )
 call s:MenuMap( 'Slim&v.&Documentation.&Hyperspec',             g:slimv_leader.'h',  g:slimv_leader.'dh',  ':call SlimvHyperspec()<CR>' )
 call s:MenuMap( 'Slim&v.&Documentation.Generate-&Tags',         g:slimv_leader.']',  g:slimv_leader.'dg',  ':call SlimvGenerateTags()<CR>' )
 
 endif
 
 " Add REPL menu. This menu exist only for the REPL buffer.
-function SlimvAddReplMenu()
+function! SlimvAddReplMenu()
     if &wildcharm != 0
         execute ':map ' . g:slimv_leader.'\ :emenu REPL.' . nr2char( &wildcharm )
     endif

File ftplugin/swank.py

 #
 # SWANK client for Slimv
 # swank.py:     SWANK client code for slimv.vim plugin
-# Version:      0.8.3
-# Last Change:  17 May 2011
+# Version:      0.8.4
+# Last Change:  27 May 2011
 # Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 # License:      This file is placed in the public domain.
 #               No warranty, express or implied.
             return unquote(lst[i+1])
     return ''
 
+def parse_location(fname, loc):
+    lnum = 1
+    cnum = 1
+    pos = loc
+    try:
+        f = open(fname, "r")
+    except:
+        return [0, 0]
+    for line in f:
+        if pos < len(line):
+            cnum = pos
+            break
+        pos = pos - len(line)
+        lnum = lnum + 1
+    f.close()
+    return [lnum, cnum]
+
+def unicode_len(text):
+    return len(unicode(text, "utf-8"))
+
 def swank_send(text):
     global sock
 
     logtime('[---Sent---]')
     logprint(text)
-    l = hex(len(text))[2:]
+    l = hex(unicode_len(text))[2:]
     t = '0'*(lenbytes-len(l)) + l + text
     if debug:
         print 'Sending:', t
                 sys.stdout.write( 'Socket error when receiving from SWANK server.\n' )
                 swank_disconnect()
                 return rec
-            while data and len(rec) < msglen:
+            while data and unicode_len(rec) < msglen:
                 rec = rec + data
-                l = l - len(data)
+                l = l - unicode_len(data)
                 if l > 0:
                     try:
                         data = sock.recv(l)
     warnings = struct[1]
     time = struct[3]
     filename = struct[5]
+    vim.command("let qflist = []")
     if type(warnings) == list:
         buf = '\n' + str(len(warnings)) + ' compiler notes:\n\n'
         for w in warnings:
                     buf = buf + snippet + '\n'
                 buf = buf + fname + ':' + pos + '\n'
                 buf = buf + '  ' + severity + ': ' + msg + '\n\n' 
+                [lnum, cnum] = parse_location(fname, int(pos))
+                qfentry = "{'filename':'"+fname+"','lnum':'"+str(lnum)+"','col':'"+str(cnum)+"','text':'"+msg+"'}"
+                logprint(qfentry)
+                vim.command("call add(qflist, " + qfentry + ")")
     else:
         buf = '\nCompilation finished. (No warnings)  [' + time + ' secs]\n\n'
+    vim.command("call setqflist(qflist)")
     return buf
 
 def swank_parse_frame_call(struct):
 ###############################################################################
 
 def swank_connection_info():
+    actions.clear()
     indent_info.clear()
     swank_rex(':connection-info', '(swank:connection-info)', 'nil', 't')
 

File slime/start-swank.lisp

  :load-contribs t)   ; load all contribs
 
 (swank:create-server :port 4005
-                     :coding-system "iso-latin-1-unix"
+                     :coding-system "utf-8-unix"
 
                      ;; if non-nil the connection won't be closed
                      ;; after connecting