[SCM] Lisaac compiler branch, master, updated. a6ea11745086a163c36945f4592c146a27486d6b

Xavier Oswald x.oswald at free.fr
Mon Nov 10 20:39:20 UTC 2008


The following commit has been merged in the master branch:
commit 6003ff2ba05d0cb0a05cf94834744a7a0ed3350e
Author: Xavier Oswald <x.oswald at free.fr>
Date:   Mon Nov 10 21:38:43 2008 +0100

     * Add JPTemplate support for vim

diff --git a/Changelog b/Changelog
index e3d94fb..9f79308 100644
--- a/Changelog
+++ b/Changelog
@@ -3,6 +3,7 @@ Version 0.14 :
 [Xavier Oswald]
  * New vim syntax coloration file (2008/11/07)
  * Update default vimrc (2008/11/06)
+ * Add JPTemplate support for vim (2008/11/10)
 
 [Benoit Sonntag]
  * Lip project path Makefile
diff --git a/editor/vim/jptemplate/lisaac/do_while b/editor/vim/jptemplate/lisaac/do_while
new file mode 100644
index 0000000..a5ba3ce
--- /dev/null
+++ b/editor/vim/jptemplate/lisaac/do_while
@@ -0,0 +1,3 @@
+{
+  ${cursor}
+}.do_while {${test expression}};
diff --git a/editor/vim/jptemplate/lisaac/for b/editor/vim/jptemplate/lisaac/for
new file mode 100644
index 0000000..9dfcf4b
--- /dev/null
+++ b/editor/vim/jptemplate/lisaac/for
@@ -0,0 +1,3 @@
+${initializer expression:0}.to (${loop test expression}) do { ${iterator:i}:INTEGER;
+  ${cursor}
+};
diff --git a/editor/vim/jptemplate/lisaac/for_step b/editor/vim/jptemplate/lisaac/for_step
new file mode 100644
index 0000000..eadea7a
--- /dev/null
+++ b/editor/vim/jptemplate/lisaac/for_step
@@ -0,0 +1,3 @@
+${initializer expression:0}.to (${loop test expression}) by(${step}) do { ${iterator:i}:INTEGER;
+  ${cursor}
+};
diff --git a/editor/vim/jptemplate/lisaac/if b/editor/vim/jptemplate/lisaac/if
new file mode 100644
index 0000000..f05210d
--- /dev/null
+++ b/editor/vim/jptemplate/lisaac/if
@@ -0,0 +1,3 @@
+(${test expression}).if {
+  ${cursor}
+};
diff --git a/editor/vim/jptemplate/lisaac/if_else b/editor/vim/jptemplate/lisaac/if_else
new file mode 100644
index 0000000..3660a1a
--- /dev/null
+++ b/editor/vim/jptemplate/lisaac/if_else
@@ -0,0 +1,5 @@
+(${test expression}).if {
+  ${cursor}
+} else {
+
+};
diff --git a/editor/vim/jptemplate/lisaac/if_elseif b/editor/vim/jptemplate/lisaac/if_elseif
new file mode 100644
index 0000000..b0d7a48
--- /dev/null
+++ b/editor/vim/jptemplate/lisaac/if_elseif
@@ -0,0 +1,5 @@
+(${test expression1}).if {
+  ${cursor}
+}.elseif {${test expression2}} then {
+
+};
diff --git a/editor/vim/jptemplate/lisaac/while_do b/editor/vim/jptemplate/lisaac/while_do
new file mode 100644
index 0000000..7edb921
--- /dev/null
+++ b/editor/vim/jptemplate/lisaac/while_do
@@ -0,0 +1,3 @@
+{${test expression}}.while_do {
+  ${cursor}
+};
diff --git a/editor/vim/plugin/jptemplate.vim b/editor/vim/plugin/jptemplate.vim
new file mode 100644
index 0000000..9833ab2
--- /dev/null
+++ b/editor/vim/plugin/jptemplate.vim
@@ -0,0 +1,369 @@
+" jptemplate.vim:
+"
+" A simple yet powerful interactive templating system for VIM.
+"
+" Version 1.5 (released 2008-07-08).
+"
+" Copyright (c) 2008 Jannis Pohlmann <jannis at xfce.org>.
+"
+" This program is free software; you can redistribute it and/or modify
+" it under the terms of the GNU General Public License as published by
+" the Free Software Foundation; either version 2 of the License, or (at
+" your option) any later version.
+"
+" This program is distributed in the hope that it will be useful, but
+" WITHOUT ANY WARRANTY; without even the implied warranty of
+" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+" General Public License for more details.
+"
+" You should have received a copy of the GNU General Public License
+" along with this program; if not, write to the Free Software
+" Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+" MA  02111-1307  USA
+
+
+" Reserved variable names
+let s:reservedVariables = ['date','shell','interactive_shell']
+
+" Variable value history
+let s:rememberedValues = {}
+
+" Characters to be escaped before the substitute() call
+let s:escapeCharacters = '&~\'
+
+
+function! jp:Initialize ()
+
+  " List for default configuration
+  let defaults = []
+
+  " Default configuration values
+  call add (defaults, ['g:jpTemplateDir', $HOME . '/.vim/jptemplate'])
+  call add (defaults, ['g:jpTemplateKey', '<C-Tab>'])
+  call add (defaults, ['g:jpTemplateDateFormat', '%Y-%m-%d'])
+  call add (defaults, ['g:jpTemplateDefaults', {}])
+  call add (defaults, ['g:jpTemplateVerbose', 0])
+
+  " Set default configuration for non-existent variables
+  for var in filter (defaults, '!exists (v:val[0])')
+    exec 'let ' . var[0] . ' = ' . string (var[1])
+  endfor
+
+endfunction
+
+
+function! jp:GetTemplateInfo ()
+
+  " Prepare info dictionary
+  let info = {}
+
+  " Get part of the line before the cursor
+  let part = getline  ('.')[0 : getpos ('.')[2]-1]
+
+  " Get start and end position of the template name
+  let info['start'] = match    (part, '\(\w*\)$')
+  let info['end']   = matchend (part, '\(\w*\)$')
+
+  " Get template name
+  let info['name']  = part[info['start'] : info['end']]
+
+  " Throw exception if no template name could be found
+  if empty (info['name'])
+    throw 'No template name found at cursor'
+  endif
+
+  " Determine directory to load the template from (skip empty directories;
+  " each directory may override the ones before)
+  for dir in filter ([ 'general', &ft ], '!empty (v:val)')
+    let filename = g:jpTemplateDir .'/'. dir .'/'. info['name']
+    if filereadable (filename)
+      let info['filename'] = filename
+    endif
+  endfor
+
+  " Throw exception if the template file does not exist in any of these
+  " directories (or is not readable)
+  if !has_key (info, 'filename')
+    throw 'Template file not found'
+  endif
+
+  " Determine indentation
+  let info['indent'] = matchstr (part, '^\s\+')
+
+  " Return template name information
+  return info
+
+endfunction
+
+
+function! jp:ReadTemplate (name, filename)
+
+  " Try to read the template file and throw exception if that fails
+  try
+    return readfile (a:filename)
+  catch
+    throw 'Template "' . a:name . '" could not be found.'
+  endtry
+
+endfunction
+
+
+function! jp:UpdateCursorPosition (lines, endColumn)
+
+  " Define cursorPosition as the column to which the cursor is moved
+  let cursorPosition = -1
+
+  for cnt in range (0, a:lines)
+    " Search for ${cursor} in the current line
+    let str    = getline  (line ('.') + cnt)
+    let start  = match    (str, '${cursor}')
+    let end    = matchend (str, '${cursor}')
+    let before = strpart  (str, 0, start)
+    let after  = strpart  (str, end)
+
+    if start >= 0
+      " Remove ${cursor} and move the cursor to the desired position
+      call setline (line ('.') + cnt, before . after)
+      call cursor (line ('.') + cnt, start+1)
+
+      let cursorPosition = start
+
+      " We're done
+      break
+    endif
+  endfor
+
+  " Update cursor position in case no ${cursor} was found in the template
+  " and the resulting template was not empty
+  if cursorPosition == -1 && a:lines >= 0
+    if a:lines == 0
+      call cursor (line ('.'), a:endColumn + 1)
+    else
+      call cursor (line ('.') + a:lines, a:endColumn + 1)
+    endif
+  endif
+
+  " Return to insert mode (distinguish between 'in the middle of the line' and
+  " 'at the end of the line')
+  if col ('.') == len (getline ('.')) 
+    startinsert!
+  else
+    startinsert
+  endif
+
+endfunction
+
+
+function! jp:ParseExpression (expr)
+
+  " Determine position of the separator between name and value
+  let valuepos = match (a:expr, ':')
+
+  " Extract name and value strings
+  let name  = valuepos >= 0 ? strpart (a:expr, 0, valuepos) : a:expr
+  let value = valuepos >= 0 ? strpart (a:expr, valuepos + 1) : ''
+
+  " Return list with both strings
+  return [name, value]
+
+endfunction
+
+
+function! jp:EvaluateReservedVariable (name, value, variables)
+
+  let result = ''
+
+  if a:name == 'date'
+    let result = strftime (empty (a:value) ? g:jpTemplateDateFormat : a:value)
+  elseif a:name == 'shell'
+    if !empty (a:value)
+      let result = system (a:value)
+    endif
+  elseif a:name == 'interactive_shell'
+    let command = input ('interactive_shell: ', a:value)
+    if !empty (command)
+      let result = system (command)
+    endif
+  endif
+
+  return result
+
+endfunction
+
+
+function! jp:ExpandTemplate (info, template)
+
+  " Backup content before and after the template name
+  let before = strpart (getline ('.'), 0, a:info['start'])
+  let after  = strpart (getline ('.'), a:info['end'])
+
+  " Merge lines of the template and then split them up again.
+  " This makes multi-line variable values possible
+  let mergedTemplate = split (join (a:template, "\n"), "\n")
+
+  " Define cnt as the number of inserted lines
+  let cnt = 0
+
+  " Remove template string if the resulting template is empty
+  if empty (mergedTemplate)
+    call setline (line ('.'), before . after)
+    call cursor (line ('.'), len (before) + 1)
+    let cnt = -1
+  else
+    " Insert template between before and after
+    for cnt in range (0, len (mergedTemplate) - 1)
+      if cnt == 0
+        call setline (line ('.'), before . mergedTemplate[cnt])
+      else
+        call append (line ('.') + cnt - 1, a:info['indent'] . mergedTemplate[cnt])
+      endif
+      if cnt == len (mergedTemplate) - 1
+        call setline (line ('.') + cnt, getline (line ('.') + cnt) . after)
+      endif
+    endfor
+  endif
+
+  " Define start and end columns of the template
+  let startColumn = len (before)
+  if empty (mergedTemplate)
+    let endColumn = startColumn
+  else
+    if cnt == 0
+      let endColumn = startColumn + len (mergedTemplate[0])
+    else
+      let endColumn = len (a:info['indent'] . mergedTemplate[len (mergedTemplate) - 1])
+    endif
+  endif
+
+  " Return number of inserted lines, start and end columns
+  return [cnt, startColumn, endColumn]
+
+endfunction
+
+
+function! jp:ProcessTemplate (info, template)
+
+  let matchpos    = 0
+  let expressions = []
+  let variables   = {}
+  let reserved    = {}
+
+  " Make a string out of the template lines
+  let s:str = join (a:template, ' ')
+
+  " Detect all variable names of the template
+  while 1
+    " Find next variable start and end position
+    let start = match    (s:str, '${[^{}]\+}', matchpos)
+    let end   = matchend (s:str, '${[^{}]\+}', matchpos)
+
+    if start < 0
+      " Stop search if there is no variable left
+      break
+    else
+      " Extract variable expression (remove '${' and '}')
+      let expr = s:str[start+2 : end-2]
+
+      " Extract variable name and default value */
+      let [name, value] = jp:ParseExpression (expr)
+
+      if name == 'cursor'
+        " Skip the ${cursor} variable
+      elseif count (s:reservedVariables, name) > 0
+        let reserved[expr] = ''
+      else
+        " Only insert variables on their first appearance
+        if !has_key (variables, name)
+          " Add expression to the expression list
+          call add (expressions, expr)
+
+          " Set variable value to ''
+          let variables[name] = ''
+        endif
+
+        " Check whether local default value is defined or not
+        if empty (value)
+          " If not, check if variable value is empty
+          if empty (variables[name])
+            " If so, either set it to the last remembered value or the global
+            " default if it exists
+            if has_key (s:rememberedValues, name)
+              let variables[name] = s:rememberedValues[name]
+            elseif has_key (g:jpTemplateDefaults, name)
+              let variables[name] = g:jpTemplateDefaults[name]
+            endif
+          endif
+        else
+          " Use local default (first occurence in the template only)
+          let variables[name] = value
+        endif
+      endif
+
+      " Start next search at the end position of this expression
+      let matchpos = end
+    endif
+  endwhile
+
+  " Ask the user to enter values for all variables
+  for expr in expressions
+    let [name, value] = jp:ParseExpression (expr)
+    let variables[name] = input (name . ': ', variables[name])
+    let s:rememberedValues[name] = variables[name]
+  endfor
+
+  " Evaluate reserved variables
+  for expr in keys (reserved)
+    let [name, value] = jp:ParseExpression (expr)
+    let replacement = jp:EvaluateReservedVariable (name, value, variables)
+    let reserved[expr] = replacement
+  endfor
+
+  " Expand all variables (custom and reserved)
+  for index in range (len (a:template))
+    for expr in expressions
+      let [name, value] = jp:ParseExpression (expr)
+      let expr = '${' . name . '\(:[^{}]\+\)\?}'
+      let value = escape(variables[name], s:escapeCharacters)
+      let a:template[index] = substitute (a:template[index], expr, value, 'g')
+    endfor
+
+    for [expr, value] in items (reserved)
+      let expr = '${' . expr . '}'
+      let value = escape(value, s:escapeCharacters)
+      let a:template[index] = substitute (a:template[index], expr, value, 'g')
+    endfor
+  endfor
+
+  " Insert template into the code line by line
+  let [insertedLines, startColumn, endColumn] = jp:ExpandTemplate (a:info, a:template)
+
+  " Update the cursor position and return to insert mode 
+  call jp:UpdateCursorPosition (insertedLines, endColumn)
+
+endfunction
+
+
+function! jp:InsertTemplate ()
+
+  try
+    " Detect bounds of the template name as well as the name itself
+    let info = jp:GetTemplateInfo ()
+
+    " Load the template file
+    let template = jp:ReadTemplate (info['name'], info['filename'])
+
+    " Do the hard work: Process the template
+    call jp:ProcessTemplate (info, template)
+  catch
+    " Inform the user about errors
+    echo g:jpTemplateVerbose ? v:exception . " (in " . v:throwpoint . ")" : v:exception
+  endtry
+
+endfunction
+
+
+" Initialize jptemplate configuration
+call jp:Initialize ()
+
+" Map keyboard shortcut to the template system
+exec 'imap ' . g:jpTemplateKey . ' <Esc>:call jp:InsertTemplate()<CR>'
diff --git a/install_lisaac.li b/install_lisaac.li
index c26d154..763d2d4 100644
--- a/install_lisaac.li
+++ b/install_lisaac.li
@@ -467,6 +467,8 @@ Section Private
       } else {
         ENVIRONMENT.execute_command "mkdir -p ~/.vim/syntax";
         ENVIRONMENT.execute_command "mkdir -p ~/.vim/indent";
+        ENVIRONMENT.execute_command "mkdir -p ~/.vim/plugin";
+        ENVIRONMENT.execute_command "mkdir -p ~/.vim/jptemplate/lisaac";
         
         // Syntax hilightning support
         string_tmp.copy "cp -f editor/vim/syntax/lisaac.vim ~/.vim/syntax/";
@@ -492,6 +494,30 @@ Section Private
           "OK.\n".print;  
         };
 
+        // JPTemplate plugin - A simple yet powerful interactive template system for VIM v1.5
+        string_tmp.copy "cp -f editor/vim/plugin/lisaac.vim ~/.vim/plugin/";
+        "  `".print;
+        string_tmp.print;
+        "'\t".print;
+        (ENVIRONMENT.execute_command string_tmp != 0).if {	
+          "\n  Sorry, auto-install fail !\n\
+          \  You can read the `editor/vim/install_vim_plugin.sh' file.\n".print;
+        } else {
+          "OK.\n".print;  
+        };
+        
+        string_tmp.copy "cp -f editor/vim/jptemplate/lisaac/* ~/.vim/jptemplate/lisaac/";
+        "  `".print;
+        string_tmp.print;
+        "'\t".print;
+        (ENVIRONMENT.execute_command string_tmp != 0).if {	
+          "\n  Sorry, auto-install fail !\n\
+          \  You can read the `editor/vim/install_vim_plugin.sh' file.\n".print;
+        } else {
+          "OK.\n".print;  
+        };
+
+
         // Install ~/.vimrc file
         char := question
         "\n  Do you want to install the default configuration provided by lisaac   \n\

-- 
Lisaac compiler



More information about the Lisaac-commits mailing list