f13a2b1ddedf

Do some horrifying things with lisp folding
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Fri, 15 Apr 2016 18:06:03 +0000
parents 1b4778f1a32a
children 08965030b28b
branches/tags (none)
files bin/ccl-rlwrap ccl-init.lisp lispwords vim/ftplugin/lisp/lispfolding.vim

Changes

--- a/bin/ccl-rlwrap	Tue Apr 12 22:01:41 2016 +0000
+++ b/bin/ccl-rlwrap	Fri Apr 15 18:06:03 2016 +0000
@@ -1,3 +1,5 @@
 #!/usr/bin/env bash
 
-rlwrap ros -L ccl-bin run -l ~/.ccl-init.lisp "$@"
+# rlwrap ros -L ccl-bin run -l ~/.ccl-init.lisp "$@"
+# roswell performance ccl is fucked atm, see here https://github.com/roswell/roswell/issues/141
+rlwrap /usr/local/bin/ccl64 "$@"
--- a/ccl-init.lisp	Tue Apr 12 22:01:41 2016 +0000
+++ b/ccl-init.lisp	Fri Apr 15 18:06:03 2016 +0000
@@ -9,8 +9,8 @@
 (setf ccl:*listener-prompt-format* #'sjl-lisp-prompt-format)
 
 ;;; The following lines added by ql:add-to-init-file:
-; #-quicklisp
-; (let ((quicklisp-init (merge-pathnames ".quicklisp/setup.lisp" (user-homedir-pathname))))
-;   (when (probe-file quicklisp-init)
-;     (load quicklisp-init)))
+#-quicklisp
+(let ((quicklisp-init (merge-pathnames ".quicklisp/setup.lisp" (user-homedir-pathname))))
+  (when (probe-file quicklisp-init)
+    (load quicklisp-init)))
 
--- a/lispwords	Tue Apr 12 22:01:41 2016 +0000
+++ b/lispwords	Fri Apr 15 18:06:03 2016 +0000
@@ -6,7 +6,7 @@
 (1 test)
 
 ; optima
-(1 match)
+(1 match ematch)
 
 ; defstar
 (2 defun*)
--- a/vim/ftplugin/lisp/lispfolding.vim	Tue Apr 12 22:01:41 2016 +0000
+++ b/vim/ftplugin/lisp/lispfolding.vim	Fri Apr 15 18:06:03 2016 +0000
@@ -1,60 +1,173 @@
-if exists('loaded_lispfolding') || &cp
-    finish
-endif
+" if exists('loaded_lispfolding') || &cp
+"     finish
+" endif
 let loaded_lispfolding=1
 
-" ---------------------------------------------------------------------------
-"  Automagic Lisp folding on defn's and defmacro's
-"
+let s:lispfold_flet_re = '\vlabels|flet'
+
+function! LispFoldingFormIsFlet()
+    " Return whether the form the cursor is on is a fletlike.
+    let old_z = @z
+
+    " Yank the next word.
+    normal! l
+    silent normal! "zyiw
+    let word = @z
+
+    let @z = old_z
+
+    " See if that next word is a fletlike thing.
+    if word =~ s:lispfold_flet_re
+        return 1
+    else
+        return 0
+    endif
+endfunction
+
+function! LispFoldingStartFlet(lnum)
+    " Return 1 when the given line is the start of a multi-line flet'ed
+    " function definition.  We want to fold those.  Return -1 if it's
+    " a single-line fletted definition.  Return 0 if it's neither.
+    "
+    " Relies on things being indented correctly to help the speed.
+    "
+    " Basically this thing is a total shitshow, turn back now.
+    "
+    " TODO: the function definitions have to be indented, fix that
+    let l = getline(a:lnum)
+    let save_cursor = getpos('.')
+
+    try
+        " A foldable flet looks like this:
+        "
+        " (flet
+        "     ((foo ()
+        "        ...)
+        "      (bar ()
+        "        ...))
+        "   body)
+        "
+
+        " Make sure the cursor's on the current line.
+        call setpos('.', [0, a:lnum, 1, 1])
+
+        " Check if the line starts with ( or ((, and move to the appropriate
+        " "start of the function form" character.
+        if l =~ '\v^\s\s\s\s+\(\(\k+( \(|$)'
+            normal! ^l
+        elseif l =~ '\v^\s\s\s\s\s+\(\k+( \(|$)'
+            normal! ^
+        else
+            return 0
+        endif
 
-function! GetLispFold()
+        let save_start = getpos('.')
+
+        " Pop up two levels in the paren stack.
+        " TODO: make sure we actually do, not that it matters in practice
+        call searchpair('(', '', ')', 'b')
+        call searchpair('(', '', ')', 'b')
+
+        if !LispFoldingFormIsFlet()
+            return 0
+        endif
+
+        " We know this is a fletthing, but if it only spans one line, bail.
+        call setpos('.', save_start)
+        if searchpairpos('(', '', ')')[0] == a:lnum
+            return -1
+        end
+
+        " congrats, u made it
+        return 1
+    finally
+        call setpos('.', save_cursor)
+    endtry
+endfunction
+
+function! LispFoldingEndFlet(lnum)
+    " Return whether we're at the last line of a multi-line fletted function.
+    let l = getline(a:lnum)
+    let save_cursor = getpos('.')
+
+    try
+        if l =~ '\v\)\)$'
+            call setpos('.', [0, a:lnum, len(l) - 1, 1])
+            let start_line = searchpairpos('(', '', ')', 'b')[0]
+
+            let r = LispFoldingStartFlet(start_line)
+            if r == 1
+                return 1
+            elseif r == -1
+                return 0
+            endif
+        endif
+
+        if l =~ '\v\)$'
+            call setpos('.', [0, a:lnum, len(l), 1])
+            let start_line = searchpairpos('(', '', ')', 'b')[0]
+
+            if LispFoldingStartFlet(start_line) == 1
+                return 1
+            endif
+        endif
+
+        return 0
+    finally
+        call setpos('.', save_cursor)
+    endtry
+endfunction
+
+function! GetLispFold(lnum)
     let inline_fn_comment_re = '\v^ *;;( .*)?$'
 
-    if getline(v:lnum) =~ '^;;;; '
+    if getline(a:lnum) =~ '^;;;; '
+        " Never fold top-level header comments
         return "0"
-    elseif getline(v:lnum) =~ '^;;; '
+    elseif getline(a:lnum) =~ '^;;; '
+        " Subheader top level comments should get folded together in level 1
         return "1"
-    elseif getline(v:lnum) =~ inline_fn_comment_re
-        if getline(v:lnum + 1) =~ inline_fn_comment_re
-            return "2"
+    elseif getline(a:lnum) =~ inline_fn_comment_re
+        " Inline function comments should increment the fold level
+        let prev = getline(a:lnum - 1) =~ inline_fn_comment_re
+        let next = getline(a:lnum + 1) =~ inline_fn_comment_re
+
+        if (!prev) && next
+            return "a1"
+        elseif prev && (!next)
+            return "s1"
         else
-            return "<2"
+            return "="
         endif
-    elseif getline(v:lnum) =~ '^; '
-        return "0"
-    elseif getline(v:lnum) =~ '^(let[*]? '
-        " let over lambda
+    elseif getline(a:lnum) =~ '^; '
+        " don't include commentary-commented lines in deeper folds than necessary
+        return "-1"
+    elseif getline(a:lnum) =~ '^(test '
+        " (test ...) folds at the top level
         return ">1"
-    elseif getline(v:lnum) =~ '^(test '
-        return ">1"
-    elseif getline(v:lnum) =~ '^(def\S\+ '
+    elseif getline(a:lnum) =~ '^(def\S\+ '
         " fuck it just fold everything that looks kinda deffy
         return ">1"
-    elseif getline(v:lnum) =~ '^\s*$'
-        let my_lispnum = v:lnum
-        let my_lispmax = line("$")
-
-        while (1)
-            let my_lispnum = my_lispnum + 1
-            if my_lispnum > my_lispmax
-                return "<1"
-            endif
-
-            let my_lispdata = getline(my_lispnum)
-
-            " If we match an empty line, stop folding
-            if my_lispdata =~ '^$'
-                return "<1"
-            else
-                return "="
-            endif
-        endwhile
+    elseif getline(a:lnum) =~ '^$' && getline(a:lnum - 1) =~ '^$'
+        return "0"
+    elseif getline(a:lnum) =~ '^$'
+        " Single blank lines fold along with the previous line, so that the
+        " blank line after a defun gets folded into the defun.
+        return "="
+    elseif LispFoldingStartFlet(a:lnum) == 1
+        " if this is a function definition in a labels/flet/etc, we want to
+        " start a new deeper fold
+        return ">2"
+    elseif LispFoldingEndFlet(a:lnum)
+        " if this is the END of a flet definition, we should pop a foldlevel
+        return "<2"
     else
         return "="
     endif
 endfunction
 
 function! TurnOnLispFolding()
-    setlocal foldexpr=GetLispFold()
+    setlocal foldexpr=GetLispFold(v:lnum)
     setlocal foldmethod=expr
+    " nnoremap <buffer> qq :echo GetLispFold(getpos('.')[1])<cr>
 endfunction