1 21 22 package org.armedbear.j; 23 24 import gnu.regexp.RE; 25 import gnu.regexp.UncheckedRE; 26 import java.awt.event.KeyEvent ; 27 28 public final class PerlMode extends AbstractMode implements Constants, Mode 29 { 30 private static final PerlMode mode = new PerlMode(); 31 32 private PerlMode() 33 { 34 super(PERL_MODE, PERL_MODE_NAME); 35 keywords = new Keywords(this); 36 } 37 38 public static final PerlMode getMode() 39 { 40 return mode; 41 } 42 43 public final boolean canIndent() 44 { 45 return true; 46 } 47 48 public final String getCommentStart() 49 { 50 return "# "; 51 } 52 53 public final SyntaxIterator getSyntaxIterator(Position pos) 54 { 55 return new PerlSyntaxIterator(pos); 56 } 57 58 public final Formatter getFormatter(Buffer buffer) 59 { 60 return new PerlFormatter(buffer); 61 } 62 63 protected void setKeyMapDefaults(KeyMap km) 64 { 65 km.mapKey('{', "electricOpenBrace"); 66 km.mapKey('}', "electricCloseBrace"); 67 km.mapKey(';', "electricSemi"); 68 km.mapKey(KeyEvent.VK_TAB, 0, "tab"); 69 km.mapKey(KeyEvent.VK_ENTER, 0, "newlineAndIndent"); 70 km.mapKey(KeyEvent.VK_T, CTRL_MASK, "findTag"); 71 km.mapKey(KeyEvent.VK_PERIOD, ALT_MASK, "findTagAtDot"); 72 km.mapKey(KeyEvent.VK_L, CTRL_MASK | SHIFT_MASK, "listTags"); 73 km.mapKey(')', "closeParen"); 74 km.mapKey(KeyEvent.VK_I, ALT_MASK, "cycleIndentSize"); 75 76 km.mapKey(KeyEvent.VK_OPEN_BRACKET, CTRL_MASK | SHIFT_MASK, "insertBraces"); 77 km.mapKey(KeyEvent.VK_BRACELEFT, CTRL_MASK | SHIFT_MASK, "insertBraces"); 79 80 km.mapKey(KeyEvent.VK_9, CTRL_MASK | SHIFT_MASK, "insertParentheses"); 81 82 km.mapKey(KeyEvent.VK_F12, 0, "wrapComment"); 83 84 if (Platform.isPlatformLinux()) { 85 km.mapKey(0xbb, CTRL_MASK | SHIFT_MASK, "insertBraces"); 88 89 km.mapKey(0xffc9, 0, "wrapComment"); } 92 93 km.mapKey(KeyEvent.VK_OPEN_BRACKET, CTRL_MASK, "fold"); 94 km.mapKey(KeyEvent.VK_CLOSE_BRACKET, CTRL_MASK, "unfold"); 95 } 96 97 public Tagger getTagger(SystemBuffer buffer) 98 { 99 return new PerlTagger(buffer); 100 } 101 102 public boolean isTaggable() 103 { 104 return true; 105 } 106 107 public boolean hasQualifiedNames() 108 { 109 return true; 110 } 111 112 public boolean isQualifiedName(String s) 113 { 114 return s.indexOf("::") >= 0; 115 } 116 117 public int getCorrectIndentation(Line line, Buffer buffer) 118 { 119 String trim = line.trim(); 120 if (trim.length() > 0) { 121 Position pos = null; 122 char c = trim.charAt(0); 123 if (c == '}') { 124 pos = matchClosingBrace(new Position(line, 125 line.getText().indexOf('}'))); 126 if (pos == null) 127 return 0; 128 if (!pos.getLine().trim().startsWith("{")) 129 pos = findBeginningOfStatement(pos); 130 } else if (c == ')') { 131 pos = findEnclosingParen(new Position(line, 132 line.getText().indexOf(')'))); 133 if (pos == null) 134 return 0; 135 if (!pos.getLine().trim().startsWith("(")) 136 pos = findBeginningOfStatement(pos); 137 } 138 if (pos != null) 139 return buffer.getIndentation(pos.getLine()); 140 141 if (isLabel(line)) 143 return 0; 144 } 145 final Line modelLine = findModel(line); 146 if (modelLine == null) 147 return 0; 148 final int indentSize = buffer.getIndentSize(); 149 int modelIndent = 0; 150 final String modelText = trimSyntacticWhitespace(modelLine.getText()); 151 if (modelText.equals("{")) { 152 modelIndent = buffer.getIndentation(modelLine); 153 if (buffer.getBooleanProperty(Property.INDENT_AFTER_BRACE)) 154 return modelIndent + indentSize; 155 else 156 return modelIndent; 157 } 158 Position pos = findBeginningOfStatement(new Position(modelLine, 0)); 159 if (pos != null) 160 modelIndent = buffer.getIndentation(pos.getLine()); 161 if (modelText.endsWith("{")) { 162 if (buffer.getBooleanProperty(Property.INDENT_AFTER_BRACE)) 163 return modelIndent + indentSize; 164 else 165 return modelIndent; 166 } 167 if (modelText.endsWith("}")) 168 return modelIndent; 169 if (modelText.endsWith(";")) 170 return modelIndent; 171 pos = findEnclosingParen(new Position(line, 0) ); 172 if (pos != null) { 173 if (pos.getLine().trim().endsWith("(") || 174 !buffer.getBooleanProperty(Property.LINEUP_ARGLIST)) { 175 return buffer.getIndentation(pos.getLine()) + indentSize; 176 } else { 177 pos.skip(1); 179 pos.skipWhitespaceOnCurrentLine(); 181 return buffer.getCol(pos); 182 } 183 } 184 if (modelText.endsWith(",")) 185 return buffer.getIndentation(modelLine); 186 187 pos = findBeginningOfStatement(new Position(line, 0)); 189 190 if (pos != null) { 191 if (line.getText().trim().startsWith("{")) { 192 if (buffer.getBooleanProperty(Property.INDENT_BEFORE_BRACE)) 193 return buffer.getIndentation(pos.getLine()) + indentSize; 194 else 195 return buffer.getIndentation(pos.getLine()); 196 } else 197 return buffer.getIndentation(pos.getLine()) + indentSize; 198 } 199 return modelIndent; 200 } 201 202 private static Line findModel(Line line) 203 { 204 for (Line modelLine = line.previous(); modelLine != null; 205 modelLine = modelLine.previous()) { 206 if (modelLine.isBlank()) 207 continue; 208 else if (modelLine.trim().startsWith("#")) 209 continue; 210 else if (isLabel(modelLine)) 211 continue; 212 else 213 return modelLine; 214 } 215 return null; 216 } 217 218 private static RE labelRE = new UncheckedRE("^\\s*[A-Za-z0-9_]+:\\s*$"); 219 220 private static boolean isLabel(Line line) 221 { 222 return labelRE.getMatch(line.getText()) != null; 223 } 224 225 private static Position findEnclosingParen(Position start) 228 { 229 PerlSyntaxIterator it = new PerlSyntaxIterator(start); 230 int count = 0; 231 char c; 232 while ((c = it.prevChar()) != SyntaxIterator.DONE) { 233 if (c == '}') 234 return null; 235 if (c == ')') { 236 ++count; 237 } else if (c == '(') { 238 if (count == 0) 239 return it.getPosition(); else 241 --count; 242 } 243 } 244 return null; 245 } 246 247 static Position findBeginningOfStatement(Position start) 248 { 249 Position pos = new Position(start); 250 if (pos.getLine().trim().startsWith("}")) { 251 Position posMatch = 252 matchClosingBrace(new Position(pos.getLine(), 0)); 253 if (posMatch != null) 254 pos = posMatch; 255 } else { 256 Position posParen = findEnclosingParen(pos); 257 if (posParen != null) 258 pos = posParen; 259 } 260 while (pos.getLine() != null) { 261 pos.setLine(pos.getLine().previous()); 262 if (pos.getLine() == null) 263 break; 264 pos.setOffset(pos.getLineLength()); 265 String s = trimSyntacticWhitespace(pos.getLine().getText()); 266 if (s.length() > 0) { 267 char c = s.charAt(s.length() - 1); 268 if (c == ';' || c == '{' || c == '}' || c == ':') 269 break; 270 } 271 } 272 if (pos.getLine() == null) { 273 pos.moveTo(start.getLine(), 0); 274 } else { 275 PerlSyntaxIterator it = new PerlSyntaxIterator(pos); 277 while (true) { 278 char c = it.nextChar(); 279 if (c == SyntaxIterator.DONE) 280 break; 281 if (c > ' ') 282 break; 283 } 284 pos = it.getPosition(); 285 } 286 return pos; 287 } 288 289 private static Position matchClosingBrace(Position start) 290 { 291 int count = 1; 292 PerlSyntaxIterator it = new PerlSyntaxIterator(start); 293 char c; 294 while ((c = it.prevChar()) != SyntaxIterator.DONE) { 295 if (c == '}') 296 ++count; 297 else if (c == '{') 298 --count; 299 if (count == 0) return it.getPosition(); 301 } 302 return null; 303 } 304 305 protected static String trimSyntacticWhitespace(String s) 308 { 309 PerlSyntaxIterator it = new PerlSyntaxIterator(null); 310 return (new String (it.hideSyntacticWhitespace(s))).trim(); 311 } 312 313 private static final String validChars = 314 "$@%ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"; 315 316 static final boolean isIdentifierChar(char c) 317 { 318 return (validChars.indexOf(c) >= 0); 319 } 320 321 public boolean isIdentifierStart(char c) 322 { 323 return isIdentifierChar(c); 324 } 325 326 public boolean isIdentifierPart(char c) 327 { 328 return isIdentifierChar(c); 329 } 330 331 public boolean isCommentLine(Line line) 332 { 333 return line.trim().startsWith("#"); 334 } 335 } 336 | Popular Tags |