--[[ Mitchell's ruby/commands.lua Copyright (c) 2006-2008 Mitchell Foral. All rights reserved. SciTE-tools homepage: http://caladbolg.net/scite.php Send email to: mitchellcaladbolgnet Permission to use, copy, modify, and distribute this file is granted, provided credit is given to Mitchell. ]]-- --- -- Commands for the ruby module. -- There are several option variables used: -- PLATFORM: OS platform (linux or windows). -- FILE_IN: Location of the temporary file used as STDIN for various -- operations. -- FILE_OUT: Location of the temporary file that will contain output for -- various operations. -- REDIRECT: The command line symbol used for redirecting STDOUT to a file. module('modules.ruby.commands', package.seeall) -- platform-specific options local PLATFORM = PLATFORM or 'linux' local FILE_IN, FILE_OUT, REDIRECT if PLATFORM == 'linux' then FILE_IN = '/tmp/scite_input' FILE_OUT = '/tmp/scite_output' REDIRECT = ' &> ' elseif PLATFORM == 'windows' then FILE_IN = os.getenv('TEMP')..'\scite_input.txt' FILE_OUT = os.getenv('TEMP')..'\scite_output.txt' REDIRECT = ' > ' end -- end options --- Patterns for auto 'end' completion for control structures. -- @class table -- @name control_structure_patterns -- @see try_to_autocomplete_end local control_structure_patterns = { '^%s*begin', '^%s*case', '^%s*class', '^%s*def', '^%s*for', '^%s*if', '^%s*module', '^%s*unless', '^%s*until', '^%s*while', 'do%s*|?.-|?%s*$' } --- -- Try to autocomplete Lua's 'end' keyword for control structures like 'if', -- 'while', 'for', etc. -- @see control_structure_patterns function try_to_autocomplete_end() editor:BeginUndoAction() editor:LineEnd() editor:NewLine() local line_num = editor:LineFromPosition(editor.CurrentPos) local line = editor:GetLine(line_num - 1) for _, patt in ipairs(control_structure_patterns) do if line:match(patt) then local indent = editor.LineIndentation[line_num - 1] editor:AddText('\nend') editor.LineIndentation[line_num + 1] = indent editor.LineIndentation[line_num] = indent + editor.Indent editor:LineUp() break end end editor:EndUndoAction() end --- -- Determine the Ruby file being 'require'd, and search through the RUBYPATH -- for that file and open it in SciTE. function goto_required() local line = editor:GetLine( editor:LineFromPosition(editor.CurrentPos) ) local _, filename = line:match('^%s*require%s*([\'"])([^%1]+)%1') os.execute("ruby -e 'puts $:'"..REDIRECT..FILE_OUT) local f = io.open(FILE_OUT) for path in f:lines() do path = path..'/'..filename..'.rb' local f2 = io.open(path) if f2 then f2:close() scite.Open(path) break end end f:close() end --- -- Perform method autocompletion via rcodetools. -- WARNING: rcodetools EXECUTES code to do its method completion. function autocomplete(char) editor:AddText(char) local txt = editor:GetText() local f = io.open(FILE_IN, 'w') f:write(txt) f:close() local line = editor:LineFromPosition(editor.CurrentPos) + 1 local col = editor.Column[editor.CurrentPos] os.execute('rct-complete --line='..line..' --column='..col.. ' '..FILE_IN..REDIRECT..FILE_OUT) f = io.open(FILE_OUT) txt = f:read('*all') f:close() if not txt:match('^[^\n]-:%d+:in') then local sep = string.char(editor.AutoCSeparator) txt = txt:gsub('[^%w_?!\n]+\n?', '') -- word methods txt = txt:gsub('\n+$', '') -- remove trailing \n's txt = txt:gsub('\n', sep) -- create completion list editor:AutoCShow(0, txt) else local text = txt:match("undefined.-'") print(txt) end end --- -- Print ri documentation via rcodetools to the SciTE output pane. function ri_doc() local pos = editor.CurrentPos if editor.CharAt[pos - 1] == 40 then pos = pos - 1 end -- '(' local txt = editor:GetText() local f = io.open(FILE_IN, 'w') f:write(txt) f:close() local line = editor:LineFromPosition(pos) + 1 local col = editor.Column[pos] os.execute('rct-doc --line='..line..' --column='..col.. ' '..FILE_IN..REDIRECT..FILE_OUT) f = io.open(FILE_OUT) txt = f:read('*all') f:close() txt = txt:match('^[^\n]*') os.execute('ri "'..txt..'"'..REDIRECT..FILE_OUT) f = io.open(FILE_OUT) txt = f:read('*all') f:close() if not txt:match('^[^\n]-:%d+:in') then txt = txt:gsub('\n+$', '') editor:CallTipShow(editor.CurrentPos, txt) else print(txt) end end --- -- Toggles between brace and do..end style Ruby blocks. -- If no text is selected, the single-line brace style block is assumed to be -- on the current line. It is converted into a do..end style block. If text is -- selected, the entire lines the beginning and end of the selection are on are -- searched for a 'do' and 'end'. When found, they are replaced by braces. function toggle_block() editor:BeginUndoAction() if editor:GetSelText() == '' then editor:LineEnd() local match_pos = editor:BraceMatch(editor.CurrentPos - 1) if match_pos > 0 then editor:SetSel(match_pos, editor.CurrentPos) local line = editor:LineFromPosition(editor.CurrentPos) local code = editor:GetSelText() code = code:gsub('^{%s*(|.-|)%s*(.-)%s*}$', 'do %1\n %2\nend') editor:ReplaceSel(code) local indent = editor.LineIndentation[line] editor.LineIndentation[line + 1] = indent + editor.Indent editor.LineIndentation[line + 2] = indent if code:match('\n \nend$') then editor:LineUp() end end else local pos1, pos2 = editor.CurrentPos, editor.Anchor if pos1 > pos2 then pos1, pos2 = pos2, pos1 end local s, _ = editor:findtext('do', 0, pos1) if s < pos2 then editor:SetSel(s, pos2) local code = editor:GetSelText() code = code:gsub('^do%s*(|.-|)%s*(.-)%s*end$', '{ %1 %2 }') editor:ReplaceSel(code) if code:match(' }$') then editor:CharLeft() editor:CharLeft() end end end editor:EndUndoAction() end -- Ruby-specific key commands local keys = _G.keys if type(keys) == 'table' then local m_functions = modules.scite.functions keys[SCLEX_RUBY].ac = { f = { l = { m_functions.show, 'def' }, a = { m_functions.show_args, 'def' }, }, t = { toggle_block }, g = { goto_required } } keys[SCLEX_RUBY]['s\n'] = { try_to_autocomplete_end } keys[SCLEX_RUBY]['cs?'] = { ri_doc } keys[SCLEX_RUBY][SCE_RB_STRING] = { ['s#'] = { modules.scite.snippets.insert, '#{${0}}' } } end