/* * Enter_with_Prefix.bsh - a Beanshell macro for jEdit * that starts a new line continuing any recognized * sequence that started the previous. For example, * if the previous line beings with "1." the next will * be prefixed with "2.". It supports alpha lists (a., b., etc...), * bullet lists (+, =, *, etc..), comments, Javadocs, * Java import statements, e-mail replies (>, |, :), * and is easy to extend with new sequence types. Suggested * shortcut for this macro is S+ENTER (SHIFT+ENTER). * * Copyright (C) 2004 Ollie Rutherfurd * * $Id$ */ import java.util.regex.Pattern; import java.util.regex.Matcher; DEBUG = false; Prefix(Matcher m){ /** leading whitespace */ this.leading = m.group(1); /** body of prefix */ this.body = m.group(2); /** trailing whitespace */ this.trailing = m.group(3); return this; } /** * Increments to next: * - "a. " -> "b. " * - "a) " -> "b) " * - "a] " -> "b] " */ AlphaList(){ name = "Alpha List"; pattern = Pattern.compile("^(\\s*(?:[|#*/>]+\\s+)?)([A-z][.)])(\\s+)"); String getNextPrefix(prefix){ char next = prefix.body.charAt(0) + 1; return prefix.leading + next + prefix.body.charAt(1) + prefix.trailing; } return this; } /** * Continues any of: * - "= " * - "* " * - "+ " */ BulletList(){ name = "Bullet List"; pattern = Pattern.compile("^(\\s*)([=*+])(\\s+)"); String getNextPrefix(prefix){ return prefix.leading + prefix.body + prefix.trailing; } return this; } /** * Continues one or more of: * - "*" * - ";" * - "#" * - "/" * - "-" */ Comment(){ name = "Comment"; pattern = Pattern.compile("^(\\s*)([*;#/-]+)(\\s*)"); String getNextPrefix(prefix){ return prefix.leading + prefix.body + prefix.trailing; } return this; } /** * Continues without leading "/": * - "/**" -> " * " * - "/*" -> " *" */ JavaDoc(){ name = "JavaDoc"; pattern = Pattern.compile("^(\\s*)(/[*]{1,2})(\\s*)"); String getNextPrefix(prefix){ return prefix.leading + (prefix.body.length() == 3 ? " * " : " *") + prefix.trailing; } return this; } /** * Continues an import statement without the class name. * "import com.foo.Blah;" -> "import com.foo." */ JavaImport(){ name = "Java Import"; pattern = Pattern.compile("^(\\b)(import\\s+)((?:[a-z]+[.])+)"); String getNextPrefix(prefix){ return prefix.leading + prefix.body + prefix.trailing; } return this; } /** * Continues any sequence of: * - "|" * - ":" * - ">" */ Generic(){ name = "Generic"; pattern = Pattern.compile("^(\\s*)([|:>]+)(\\s*)"); String getNextPrefix(prefix){ return prefix.leading + prefix.body + prefix.trailing; } return this; } /** * Increments to next: * - "1. " -> "2. " * - "1) " -> "2) " * - "1] " -> "2] " */ NumberedList(){ name = "Numbered List"; pattern = Pattern.compile("^(\\s*(?:[|#*/>]+\\s+)?)([0-9]+[.)])(\\s+)"); String getNextPrefix(prefix){ int next = Integer.parseInt(prefix.body.substring(0,prefix.body.length()-1)) + 1; return prefix.leading + next + prefix.body.substring(prefix.body.length()-1) + prefix.trailing; } return this; } /** * Continues: * - '+ "' * - "+ '" */ MultiLineString(){ name = "Multi-line String"; pattern = Pattern.compile("^(\\s+)([+]\\s*[\"'])(\\s*)"); String getNextPrefix(prefix){ return prefix.leading + prefix.body + prefix.trailing; } return this; } /** * Continues sequence of non-alpha characters or spaces. */ NonAlpha(){ name = "(Non-Alpha)"; pattern = Pattern.compile("^(\\s*)([^A-z ]+)(\\s*)"); String getNextPrefix(prefix){ return prefix.leading + prefix.body + prefix.trailing; } return this; } /** * Returns object containing: * - leading (usually whitespace) * - body (of prefix) * - trailing (usually whitespace) * or null if no match. */ getPrefix(String line, scheme){ Matcher m = scheme.pattern.matcher(line); if(DEBUG) Macros.message(view, "checking: '" + line + "'\n" + "scheme: " + scheme.name + "\n" + "pattern: " + scheme.pattern.pattern() + "\n" + "matches: " + m.lookingAt()); if(m.lookingAt() == false) return null; p = Prefix(m); // hack to prevent NonAlpha from // screwing up standard indentation if("".equals(p.body.trim())){ if(DEBUG) Macros.message(view, "Skipping because 'body' is all whitespace"); return null; } return p; } insertNewlineWithPrefix(View view){ // as there's overlap between which // regex's match, the ordering // here is significant. Object[] schemes = {NumberedList(), AlphaList(), MultiLineString(), BulletList(), JavaImport(), JavaDoc(), Comment(), Generic(), NonAlpha(), }; JEditTextArea textArea = view.getTextArea(); String line = textArea.getLineText(textArea.getCaretLine()); for(int i=0; i < schemes.length; i++){ p = getPrefix(line,schemes[i]); if(p != null){ String prefix = schemes[i].getNextPrefix(p); view.getStatus().setMessageAndClear("Continued " + schemes[i].name); textArea.setSelectedText(""); int caret = textArea.getCaretPosition(); textArea.getBuffer().insert(caret,"\n" + prefix); textArea.setCaretPosition(caret + prefix.length() + 1); return; } } view.getStatus().setMessageAndClear("No match found"); // didn't find a match, use fallback behavior textArea.insertEnterAndIndent(); } insertNewlineWithPrefix(view); // :deepIndent=true: