org.netbeans.modules.languages.features.IndentAction Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.languages.features;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.regex.Pattern;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.StyledDocument;
import org.netbeans.api.languages.Context;
import org.netbeans.api.languages.LanguageDefinitionNotFoundException;
import org.netbeans.api.lexer.Token;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.api.lexer.TokenSequence;
import org.netbeans.editor.BaseDocument;
import org.netbeans.editor.BaseKit.InsertBreakAction;
import org.netbeans.modules.languages.Feature;
import org.netbeans.modules.languages.Feature.Type;
import org.netbeans.modules.languages.Language;
import org.netbeans.modules.languages.LanguagesManager;
import org.openide.ErrorManager;
import org.openide.text.NbDocument;
/**
*
* @author Jan Jancura
*/
public class IndentAction extends InsertBreakAction {
protected void afterBreak (
JTextComponent target,
BaseDocument doc,
Caret caret,
Object cookie
) {
try {
TokenHierarchy th = TokenHierarchy.get (doc);
TokenSequence ts = th.tokenSequence ();
ts.move (caret.getDot ());
if (ts.moveNext ())
while (ts.embedded () != null) {
ts = ts.embedded ();
ts.move (caret.getDot ());
if (!ts.moveNext ()) break;
}
Language l = LanguagesManager.getDefault ().getLanguage (ts.language ().mimeType ());
Token token = ts.token ();
Object indentValue = getIndentProperties (l);
if (indentValue == null) return;
if (indentValue instanceof Object[]) {
Object[] params = (Object[]) indentValue;
int length = doc.getLength();
int ln = NbDocument.findLineNumber ((StyledDocument) doc, caret.getDot () - 1);
int endLine = NbDocument.findLineNumber ((StyledDocument) doc, length - 1);
int start = NbDocument.findLineOffset ((StyledDocument) doc, ln);
int end = ln < endLine ? NbDocument.findLineOffset ((StyledDocument) doc, ln + 1) : length;
String line = doc.getText (start, end - start);
int indent = getIndent (line);
ts.move (start);
ts.moveNext ();
int ni = getIndent (line, ts, end, params);
if (ni > 0)
indent += 4;
else
if (ni == 0 && ln > 0) {
int start1 = NbDocument.findLineOffset ((StyledDocument) doc, ln - 1);
line = doc.getText (start1, start - start1);
ts.move (start1);
ts.moveNext ();
ni = getIndent (line, ts, start, params);
if (ni == 2)
indent -= 4;
}
try {
start = NbDocument.findLineOffset ((StyledDocument) doc, ln + 1);
try {
end = NbDocument.findLineOffset ((StyledDocument) doc, ln + 2);
line = doc.getText (start, end - start);
} catch (IndexOutOfBoundsException ex) {
line = doc.getText (start, doc.getLength () - start);
}
} catch (IndexOutOfBoundsException ex) {
line = null;
}
indent (doc, caret.getDot (), indent);
if ( line != null &&
((Set) params [2]).contains (line.trim ())
) {
indent -= 4;
int offset = caret.getDot ();
doc.insertString (offset, "\n", null);
indent (doc, caret.getDot (), indent);
caret.setDot (offset);
}
} else
if (indentValue instanceof Feature) {
Feature m = (Feature) indentValue;
m.getValue (Context.create (doc, ts.offset ()));
}
} catch (LanguageDefinitionNotFoundException ldnfe) {
//no language found - this might happen when some of the embedded languages are not schliemann based,
//so just ignore and do nothing - no indent
} catch (Exception ex) {
ErrorManager.getDefault ().notify (ex);
}
}
private static int getIndent (String line) {
int indent = 0;
int i = 0, k = line.length () - 1;
while (i < k && Character.isWhitespace (line.charAt (i))) {
if (line.charAt(i) == '\t') {
indent += 8 - indent % 8;
} else {
indent++;
}
i++;
}
return indent;
}
private static int getIndent (
String line,
TokenSequence ts,
int end,
Object[] params
) {
Map p = new HashMap ();
do {
Token t = ts.token ();
String id = t.text ().toString ();
if (((Set) params [1]).contains (id)) {
Integer i = (Integer) p.get (id);
if (i == null) {
i = Integer.valueOf (1);
} else
i = Integer.valueOf (i.intValue () + 1);
p.put (id, i);
}
if (((Set) params [2]).contains (t.text ().toString ())) {
id = (String) ((Map) params [3]).get (id);
Integer i = (Integer) p.get (id);
if (i == null) {
i = Integer.valueOf (-1);
} else
i = Integer.valueOf (i.intValue () - 1);
p.put (id, i);
}
if (!ts.moveNext ()) break;
} while (ts.offset () < end);
Iterator it = p.values ().iterator ();
while (it.hasNext ()) {
int i = ((Integer) it.next ()).intValue ();
if (i > 0) return 1;
if (i < 0) return -1;
}
it = ((List) params [0]).iterator ();
while (it.hasNext ()) {
Pattern pattern = (Pattern) it.next ();
if (pattern.matcher (line).matches ())
return 2;
}
return 0;
}
private static void indent (Document doc, int offset, int i) {
StringBuilder sb = new StringBuilder ();
while (i > 0) {
sb.append (' ');i--;
}
try {
doc.insertString (offset, sb.toString (), null);
} catch (BadLocationException ex) {
ErrorManager.getDefault ().notify (ex);
}
}
private static Map indentProperties = new WeakHashMap ();
private static Object getIndentProperties (Language l) {
if (!indentProperties.containsKey (l)) {
List patterns = new ArrayList ();
Set start = new HashSet ();
Set end = new HashSet ();
Map endToStart = new HashMap ();
List indents = l.getFeatureList ().getFeatures ("INDENT");
Iterator it = indents.iterator ();
while (it.hasNext ()) {
Feature indent = it.next ();
if (indent.getType () == Type.METHOD_CALL) {
return indent;
}
String s = (String) indent.getValue ();
int i = s.indexOf (':');
if (i < 1) {
patterns.add (Pattern.compile (c (s)));
continue;
}
start.add (s.substring (0, i));
end.add (s.substring (i + 1));
endToStart.put (s.substring (i + 1), s.substring (0, i));
}
indentProperties.put (
l,
new Object[] {patterns, start, end, endToStart}
);
}
return indentProperties.get (l);
}
private static String c (String s) {
s = s.replace ("\\n", "\n");
s = s.replace ("\\r", "\r");
s = s.replace ("\\t", "\t");
s = s.replace ("\\\"", "\"");
s = s.replace ("\\\'", "\'");
s = s.replace ("\\\\", "\\");
return s;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy