2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
13 package org.scilab.modules.xpad.style;
15 import java.awt.Color;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.Hashtable;
19 import java.util.Vector;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
23 import javax.swing.SwingUtilities;
24 import javax.swing.event.DocumentEvent;
25 import javax.swing.event.DocumentListener;
26 import javax.swing.event.UndoableEditEvent;
27 import javax.swing.text.BadLocationException;
28 import javax.swing.text.DefaultStyledDocument;
29 import javax.swing.text.Document;
30 import javax.swing.text.Element;
31 import javax.swing.text.Style;
32 import javax.swing.text.StyleConstants;
33 import javax.swing.undo.UndoManager;
35 import org.scilab.modules.xpad.ScilabKeywords;
36 import org.scilab.modules.xpad.Xpad;
37 import org.scilab.modules.xpad.actions.ColorizeAction;
38 import org.scilab.modules.xpad.actions.IndentAction;
39 import org.scilab.modules.xpad.utils.ConfigXpadManager;
41 public class ScilabStyleDocument extends DefaultStyledDocument implements DocumentListener {
43 private UndoManager undo = new UndoManager() {
44 public void undoableEditHappened(UndoableEditEvent e) {
46 if ( (EventType.equals(DocumentEvent.EventType.INSERT.toString()) || EventType.equals(DocumentEvent.EventType.REMOVE.toString()) ) && (e.getEdit().canUndo()) ){
48 if ( EventType.equals(DocumentEvent.EventType.REMOVE.toString())){
49 System.out.println("remove");
50 System.out.println(indentInprogress) ;
53 if (!indentInprogress){
54 undo.addEdit(e.getEdit());
64 private boolean autoIndent = false;
65 private boolean autoColorize = true;
66 private boolean colorizeInprogress = false;
67 private boolean indentInprogress = false;
68 private boolean updaterDisabled = false;
70 private String EventType ;
72 //private final String[] quotations = {"[^A-Z](\"|')[^{\n}]*?(\"|')"};
73 private final String[] quotations = {"(\"|')[^{\n}]*?(\"|')"};
74 private final String[] bools = {"%T", "%F", "%t", "%f"};
75 private final String[] comments = {"//[^{\n}]*", "/\\*.*?\\*/"};
76 private final String[] operators = {"=", "\\+", "-", "\\*", "/", "\\\\", "\\^",
77 "\\./", "\\.\\\\", "\\.\\^",
78 "\\.\\*\\.", "\\./\\.", "\\.\\\\\\.",
79 "==", "<", ">", "<=", ">=", "~=", "@=",
83 private final String IN = "IN";
84 private final String OUT = "OUT";
85 private final String TABULATION = " ";
86 private final int BOOLS = 0;
87 private final int COMMANDS = 1;
88 private final int COMMENTS = 2;
89 private final int FUNCTIONS = 3;
90 private final int MACROS = 4;
91 private final int OPERATORS = 5;
92 private final int QUOTATIONS = 6;
94 private int lineStartPosition;
95 private int lineEndPosition;
96 private boolean singleLine = false;
97 private int currentLine;
99 private boolean contentModified ;
101 //private XpadStyles xpadStyles ;
103 Hashtable<String, String[]> keywords;
110 /*if you want to add a new style just add it in the xml*/
111 private ArrayList<String> listStylesName ;
112 //private final String[] allStyles = {"Operator", "Command","String","Bool" ,"Comment"} ;
113 private Style defaultStyle;
116 public ScilabStyleDocument(Xpad editor) {
118 EventType = new String();
120 this.editor = editor ;
121 Hashtable< String, Color>stylesColorsTable = ConfigXpadManager.getAllForegroundColors();
122 Hashtable< String, Boolean>stylesIsBoldTable = ConfigXpadManager.getAllisBold() ;
123 listStylesName = ConfigXpadManager.getAllStyleName();
125 //xpadStyles = XpadStyles.getInstance() ;
126 addDocumentListener(this);
127 addUndoableEditListener(undo);
128 defaultStyle = this.addStyle("Default", null);
129 StyleConstants.setBold(defaultStyle, stylesIsBoldTable.get("Default"));
130 StyleConstants.setFontFamily(defaultStyle, ConfigXpadManager.getFont().getFontName() );
131 StyleConstants.setForeground(defaultStyle, stylesColorsTable.get("Default"));
132 StyleConstants.setFontSize(defaultStyle, ConfigXpadManager.getFontSize());
133 StyleConstants.setLeftIndent(defaultStyle, 0);
135 /* set default style settings*/
136 /*that way if we want to had a new style, we just need to had an element to the xml*/
137 for(int i = 0 ; i < listStylesName.size() ; ++i) {
138 Style otherStyle = this.addStyle(listStylesName.get(i), defaultStyle);
139 StyleConstants.setBold(otherStyle, stylesIsBoldTable.get(listStylesName.get(i)));
140 StyleConstants.setForeground(otherStyle, stylesColorsTable.get(listStylesName.get(i)));
143 loadingsForColorisation();
144 setContentModified(false );
146 this.addDocumentListener( new DocumentListener(){
148 public void changedUpdate(DocumentEvent documentEvent) {
151 public void insertUpdate(DocumentEvent documentEvent) {
152 handleEvent(documentEvent);
154 public void removeUpdate(DocumentEvent documentEvent) {
155 handleEvent(documentEvent);
157 private void handleEvent(DocumentEvent documentEvent) {
158 DocumentEvent.EventType type = documentEvent.getType();
159 if (type.equals(DocumentEvent.EventType.INSERT) || type.equals(DocumentEvent.EventType.REMOVE) ) {
161 int index = getEditor().getTabPane().getSelectedIndex();
162 if ( ! isContentModified()){
163 getEditor().getTabPane().setTitleAt( index , "*" + getEditor().getTabPane().getTitleAt(index ) );
165 setContentModified(true);
176 * DOCUMENT COLORISATION START
179 public void loadingsForColorisation() {
180 // Scilab keywords to be colored
181 keywords = getScilabKeywords();
182 commands = (String[])keywords.get("command");
183 functions = (String[])keywords.get("function");
184 macros = (String[])keywords.get("macro");
186 // Regexp for Scilab keywords (for commands, functions & macros)
187 for (int i = 0; i < commands.length; i++) {
188 commands[i] = "\\b" + commands[i] + "\\b";
190 for (int i = 0; i < functions.length; i++) {
191 functions[i] = "\\b" + functions[i] + "\\b";
193 for (int i = 0; i < macros.length; i++) {
194 macros[i] = "\\b" + macros[i] + "\\b";
198 public void colorize() {
202 // We parse all words which are susceptible to be colored
203 Vector<Vector<Integer>> boundaries_list = parse(bools, commands, comments, functions, macros, operators, quotations, singleLine, 0, 0);
205 if (!colorizeInprogress) {
206 colorizeInprogress = true;
207 this.removeUndoableEditListener(undo);
208 this.addUndoableEditListener(null);
211 applyStyle(boundaries_list.elementAt(BOOLS), getStyle("Bool"));
212 applyStyle(boundaries_list.get(COMMANDS), getStyle("Command"));
213 applyStyle(boundaries_list.get(FUNCTIONS), getStyle("Function"));
214 applyStyle(boundaries_list.get(MACROS), getStyle("Macro"));
215 applyStyle(boundaries_list.get(OPERATORS), getStyle("Operator"));
216 applyStyle(boundaries_list.get(QUOTATIONS), getStyle("String"));
217 applyStyle(boundaries_list.get(COMMENTS), getStyle("Comment"));
218 } catch (BadLocationException e) {
222 this.addUndoableEditListener(undo);
223 colorizeInprogress = false;
229 public void colorizeSingleLine(int lineStartPosition, int lineEndPosition) {
233 // We parse all words which are susceptible to be colored
234 Vector<Vector<Integer>> boundaries_list = parse(bools, commands, comments, functions, macros, operators, quotations, singleLine, lineStartPosition, lineEndPosition);
236 if (!colorizeInprogress) {
237 colorizeInprogress = true;
238 this.removeUndoableEditListener(undo);
239 this.addUndoableEditListener(null);
240 resetSingleLineStyle(lineStartPosition, lineEndPosition);
242 applyStyleToSingleLine(boundaries_list.elementAt(BOOLS), getStyle("Bool"), lineStartPosition, lineEndPosition);
243 applyStyleToSingleLine(boundaries_list.get(COMMANDS), getStyle("Command"), lineStartPosition, lineEndPosition);
244 applyStyleToSingleLine(boundaries_list.get(FUNCTIONS), getStyle("Function"), lineStartPosition, lineEndPosition);
245 applyStyleToSingleLine(boundaries_list.get(MACROS), getStyle("Macro"), lineStartPosition, lineEndPosition);
246 applyStyleToSingleLine(boundaries_list.get(OPERATORS), getStyle("Operator"), lineStartPosition, lineEndPosition);
247 applyStyleToSingleLine(boundaries_list.get(QUOTATIONS), getStyle("String"), lineStartPosition, lineEndPosition);
248 applyStyleToSingleLine(boundaries_list.get(COMMENTS), getStyle("Comment"), lineStartPosition, lineEndPosition);
249 } catch (BadLocationException e) {
253 this.addUndoableEditListener(undo);
254 colorizeInprogress = false;
259 public Style getStyle(String styleName ){
260 Style plop = xpadStyles.getStyle(styleName);
265 private void resetStyle() {
267 this.removeUndoableEditListener(undo);
268 this.setCharacterAttributes(0, this.getLength(), this.getStyle("Default"), true);
269 this.setParagraphAttributes(0, this.getLength(), this.getStyle("Default"), true);
270 this.addUndoableEditListener(undo);
273 private void resetSingleLineStyle(int line_start, int line_end) {
275 this.removeUndoableEditListener(undo);
276 this.setCharacterAttributes(line_start, line_end-line_start, this.getStyle("Default"), true);
277 this.setParagraphAttributes(line_start, line_end-line_start, this.getStyle("Default"), true);
278 this.addUndoableEditListener(undo);
282 private void applyStyle(Vector<Integer> boundaries, Style style) throws BadLocationException {
283 for(int i = 0 ; i < boundaries.size() ; i=i+2) {
284 this.setCharacterAttributes(boundaries.elementAt(i), boundaries.elementAt(i+1)-boundaries.elementAt(i), style, false);
285 this.setParagraphAttributes(boundaries.elementAt(i), boundaries.elementAt(i+1)-boundaries.elementAt(i), style, false);
289 private void applyStyleToSingleLine(Vector<Integer> boundaries, Style style, int start, int end) throws BadLocationException {
290 for(int i = 0 ; i < boundaries.size() ; i=i+2) {
291 this.setCharacterAttributes(boundaries.elementAt(i), boundaries.elementAt(i+1)-boundaries.elementAt(i), style, false);
292 this.setParagraphAttributes(boundaries.elementAt(i), boundaries.elementAt(i+1)-boundaries.elementAt(i), style, false);
296 public boolean getColorize() {
297 //DEBUG("setColorize("+autoColorize+")");
301 public void setColorize(boolean b) {
302 //DEBUG("setColorize("+b+")");
306 * DOCUMENT COLORISATION END
311 * DOCUMENT INDENTATION START
313 public void indent() {
314 if (!indentInprogress) {
316 indentInprogress = true;
319 applySelectionIndent();
322 indentInprogress = false;
327 public void applyIndent(int start, int end, String previous_tab, int level_one) throws BadLocationException {
329 String indentedText = "";
330 boolean got_case = false;
332 String text_to_indent = ""; // the entire document
333 Vector<String> command_list = new Vector<String>(); // list of commands in the document
336 // Get the document text to indent
337 text_to_indent = this.getText(start, end-start);
338 } catch (BadLocationException e) {
342 // Get all line break positions &
343 // each line of the document
344 Vector<Integer> line_break = new Vector<Integer>(); // positions of line break
345 Vector<String> all_lines = new Vector<String>(); // the document line by line
347 for (int i = 0; i < text_to_indent.length(); i++) {
348 line = line.concat(text_to_indent.charAt(i)+"");
350 if (text_to_indent.charAt(i)=='\n') {
355 if (i==text_to_indent.length()-1) {
361 Vector<String> all_lines_without_spaces = new Vector<String>(); // the document line by line
363 for (int i = 0; i < all_lines.size(); i++) {
364 String no_space_line = removeFirstSpaces(all_lines.elementAt(i));
365 all_lines_without_spaces.add(no_space_line);
368 boolean got_select = false;
369 int indent_level = 0;
370 indent_level = level_one;
372 for (int i = 0; i < all_lines_without_spaces.size(); i++) {
374 //System.out.println("indent_level["+ (i+1) +"] = " + indent_level);
376 // Get commands for each lines
377 command_list = getOperatorList(all_lines_without_spaces.elementAt(i));
379 // Check if in one line all operators are matching,
380 // so we can know if the next line needs indentation or not
381 // ex: if %T then function foo(1) endfunction end => doesn't need indentation
382 // Warning: vector_match looks like [IN, if, IN function, OUT, endfunction, OUT, end]
383 Vector<String> vector_match = matchingOperators(command_list);
386 indentedText += previous_tab;
388 // Here start the indentation process
389 if (vector_match.size() > 0) {
391 // If we have 'IN' command
392 if (vector_match.elementAt(0).equals(IN)) {
394 for (int j = 0; j < indent_level; j++) {
395 indentedText += TABULATION;
398 if ((vector_match.elementAt(1).toLowerCase().equals("else")) ||
399 (vector_match.elementAt(1).toLowerCase().equals("elseif"))) {
401 if (indentedText.length() >= 2) {
402 String text_tab = indentedText.substring(indentedText.length()-2, indentedText.length());
403 if (text_tab.equals(" ") && indent_level > 0) {
404 indentedText = indentedText.substring(0, indentedText.length()-2);
410 } else if (vector_match.elementAt(1).toLowerCase().equals("select")) {
414 // If we have 'case' command, case needs 'select' to be correct
415 } else if ((vector_match.elementAt(1).toLowerCase().equals("case")) &&
416 (got_case == false) && (got_select == true) ) {
423 indentedText += all_lines_without_spaces.elementAt(i);
426 // If we have "OUT' operator
427 } else if (vector_match.elementAt(0).equals(OUT)) {
429 if (indent_level > 0) {
433 for (int j = 0; j < indent_level; j++) {
434 indentedText += TABULATION;
437 if (got_select == true && got_case == true &&
438 vector_match.elementAt(1).toLowerCase().equals("end")) {
443 // If we have only an OUT command to indent
445 if (autoIndent == true && all_lines_without_spaces.size() == 1 && level_one == 0) {
446 indentedText = previous_tab + all_lines_without_spaces.elementAt(i);
447 if (indentedText.length() >= 2) {
448 String text_tab = indentedText.substring(0, 2);
449 if (text_tab.equals(" ")) {
450 indentedText = indentedText.substring(2, indentedText.length());
456 indentedText += all_lines_without_spaces.elementAt(i);
460 for (int j = 0; j < indent_level; j++) {
461 indentedText += TABULATION;
463 indentedText += all_lines_without_spaces.elementAt(i);
466 if (indent_level > 0) {
471 vector_match.clear();
473 //System.out.println("_______________indent_level["+ (i+1) +"] = " + indent_level);
477 // Display the indentation
478 this.replace(start, end-start, indentedText, null);
480 // ATTENTION, ces cas ne sont pas traité:
481 // - gestion des commentaire /* */
482 // - analyser la ligne du document qui est modifie et non plus le document en entier pour la colorisation
483 // dans le cas d'une quotation ou commentaire(/* */) analyser le document en entier
487 public void applySelectionIndent() {
489 editor = getEditor();
491 int selection_start = 0;
492 int selection_end = 0;
495 // Get start & end offsets of the selected text
496 selection_start = editor.getTextPane().getSelectionStart();
497 selection_end = editor.getTextPane().getSelectionEnd();
500 // Get start offsets of the first selected line & end offsets of the last selected line
501 lineStartPosition = this.getParagraphElement(selection_start).getStartOffset();
502 lineEndPosition = this.getParagraphElement(selection_end).getEndOffset()-1;
505 System.out.println(lineStartPosition);
506 System.out.println(lineEndPosition);
508 if (lineStartPosition == 0) {
512 int previous_line_start = this.getParagraphElement(lineStartPosition-1).getStartOffset();
513 int previous_line_end = this.getParagraphElement(lineStartPosition-1).getEndOffset()-1;
514 String previous_line = "";
516 int current_line_start = this.getParagraphElement(selection_start).getStartOffset();
517 int current_line_end = this.getParagraphElement(selection_end).getEndOffset()-1;
518 String current_line = "";
521 previous_line = this.getText(previous_line_start, previous_line_end-previous_line_start);
522 current_line = this.getText(current_line_start, current_line_end-current_line_start);
523 // Get previous line's tabulation
524 tab = getLineTabulations(previous_line);
525 // Check if we have commands and if they match in the previous line
526 Vector<String> previous_command_list = getOperatorList(previous_line);
527 Vector<String> previous_vector_match = matchingOperators(previous_command_list);
529 // Check if we have commands and if they match in the current line
530 Vector<String> current_command_list = getOperatorList(current_line);
531 Vector<String> current_vector_match = matchingOperators(current_command_list);
533 if (previous_vector_match.size() > 0) {
534 if (previous_vector_match.elementAt(0).equals(IN)) {
541 } catch (BadLocationException e) {
547 applyIndent(lineStartPosition, lineEndPosition, tab, level_one);
549 } catch (BadLocationException e) {
555 public String getLineTabulations(String line) {
558 for (int j = 0; j < line.length(); j++) {
559 if ((line.charAt(j) == '\t') || (line.charAt(j) == ' ')) {
560 spaces = spaces.concat(line.charAt(j)+"");
570 * Remove all spaces or tabulations at the begining a string
571 * This function is used for the indentation only
572 * ex: ' hello world' will be tranformed into 'hello world'
574 public String removeFirstSpaces(String line) {
577 for (int j = 0; j < line.length(); j++) {
578 if ((line.charAt(j) == '\t') || (line.charAt(j) == ' ')) {
584 line = line.substring(spaces, line.length());
590 * Get all commands given in the string
591 * This function is used for the indentation only
593 public Vector<String> getOperatorList(String text) {
594 Vector<String> operator_list = new Vector<String>();
595 Vector<String> op = new Vector<String>();
597 Vector<Integer> comments_boundaries = new Vector<Integer>();
598 Vector<Integer> quotations_boundaries = new Vector<Integer>();
599 Vector<Integer> tmp_comm_and_quot = new Vector<Integer>();
601 Vector<Integer> commands_boundaries = new Vector<Integer>();
603 String[] commands_in = {"if", "else", "elseif", "while", "for", "do", "select", "case", "function"};
604 String[] commands_out = {"end", "endfunction"};
606 String[] allCommands = {"if", "else", "elseif", "while", "for", "do", "select", "case", "function", "end", "endfunction"};
608 // Regexp for Scilab commands
609 for (int i = 0; i < allCommands.length; i++) {
610 allCommands[i] = "\\b" + allCommands[i] + "\\b";
613 // Find command boundaries in the given text
614 commands_boundaries = findBoundaries(allCommands, false, 0, this.getLength(), text);
615 comments_boundaries = findBoundaries(comments, false, 0, this.getLength(), text);
616 quotations_boundaries = findBoundaries(quotations, false, 0, this.getLength(), text);
618 // Remove comments which are into quotations
619 comments_boundaries = startNotIn(comments_boundaries, quotations_boundaries);
620 // Remove quotations which are into comments
621 quotations_boundaries = startNotIn(quotations_boundaries, comments_boundaries);
623 // Union of comments & quotations to remove keywords
624 tmp_comm_and_quot.addAll(comments_boundaries);
625 tmp_comm_and_quot.addAll(quotations_boundaries);
627 // Remove commads which are into quotations or comments
628 commands_boundaries = startNotIn(commands_boundaries, tmp_comm_and_quot);
630 // Sort commands_boudaries
631 Collections.sort(commands_boundaries);
633 // The function applyIndent needs a vector in this format, ex: IN,IF,OUT,END
634 for (int i = 0; i < commands_boundaries.size(); i=i+2) {
635 op.add(text.substring(commands_boundaries.elementAt(i), commands_boundaries.elementAt(i+1)));
638 for (int i = 0; i < op.size(); i++) {
639 for (int j = 0; j < commands_in.length; j++) {
640 if (op.elementAt(i).toLowerCase().equals(commands_in[j])) {
641 operator_list.add(IN);
642 operator_list.add(op.elementAt(i));
645 for (int j = 0; j < commands_out.length; j++) {
646 if (op.elementAt(i).toLowerCase().equals(commands_out[j])) {
647 operator_list.add(OUT);
648 operator_list.add(op.elementAt(i));
653 return operator_list;
657 * Check if in one line all commands are matching,
658 * by this way we can know if the next line needs indentation or not
659 * ex: if %T then function foo(1) endfunction end => doesn't need indentation
660 * ex: if %T then foo(1) end for => need indentation
661 * This function is used for the indentation only
662 * WARNING: command_list looks like [IN, if, IN function, OUT, endfunction, OUT, end]
664 public Vector<String> matchingOperators(Vector<String> command_list) {
666 int tmp_size = command_list.size();
668 for (int i = 0; i < command_list.size() - 3; i=i+2) {
669 if ((command_list.elementAt(i+1).toLowerCase().equals("function") &&
670 command_list.elementAt(i+3).toLowerCase().equals("endfunction"))
672 (command_list.elementAt(i+3).toLowerCase().equals("end") &&
673 !(command_list.elementAt(i+1).toLowerCase().equals("function")) &&
674 !(command_list.elementAt(i+1).toLowerCase().equals("endfunction")) &&
675 !(command_list.elementAt(i+1).toLowerCase().equals("end")) )) {
676 command_list.removeElementAt(i+3);
677 command_list.removeElementAt(i+2);
678 command_list.removeElementAt(i+1);
679 command_list.removeElementAt(i);
683 if (tmp_size == command_list.size()) {
686 return matchingOperators(command_list);
689 * DOCUMENT INDENTATION END
694 * DOCUMENT COMMENT ACTION
696 public void commentText(int start_position, int end_position) {
698 String text_to_comment = "";
700 // Get the document text to comment
701 text_to_comment = this.getText(start_position, end_position-start_position);
702 } catch (BadLocationException e) {
706 Vector<Integer> line_break = new Vector<Integer>(); // positions of line break
707 Vector<String> all_lines = new Vector<String>(); // the document line by line
710 if (start_position != end_position) {
711 for (int i = 0; i < text_to_comment.length(); i++) {
712 line = line.concat(text_to_comment.charAt(i)+"");
714 if (text_to_comment.charAt(i)=='\n') {
719 if (i==text_to_comment.length()-1) {
725 String commented_text = "";
726 for (int i = 0; i < all_lines.size(); i++) {
728 if (!(all_lines.elementAt(i).equals(""))) {
729 if (all_lines.elementAt(i).length() >= 2) {
730 if (all_lines.elementAt(i).substring(0, 2).equals("//")) {
731 tmp = all_lines.elementAt(i).substring(2, all_lines.elementAt(i).length());
733 tmp = "//" + all_lines.elementAt(i);
737 commented_text += tmp;
740 // Display the text commented
742 this.replace(start_position, end_position-start_position, commented_text, null);
743 } catch (BadLocationException e) {
752 * DOCUMENT COMMENT ACTION END
757 * FIND AND REPLACE START
759 public ArrayList<Integer[]> findWord(String word, boolean caseSensitive , boolean wholeWord , boolean useRegexp ) {
760 String fullText = getFullDocument();
762 int wordSize = word.length();
763 ArrayList<Integer[]> offsetList = new ArrayList<Integer[]>();
765 //If we don't give any word to find
766 if ( (word != null) && !(word.equals("")) ) {
767 // prepare word for each kind of search
769 word = "\\b" + word + "\\b" ;
772 if (useRegexp || wholeWord ){
773 word = "(?i)" + word ;
776 fullText = fullText.toLowerCase();
777 word = word.toLowerCase();
782 //We find matching words ...
783 // ... for regexp or whole words
784 if (useRegexp || wholeWord){
785 Pattern pattern = Pattern.compile(word);
786 Matcher matcher = pattern.matcher(fullText);
788 while (matcher.find()) {
789 offsetList.add(new Integer[] {matcher.start() ,matcher.end()});
791 // ... for other case
793 while ((lastIndex = fullText.indexOf(word, lastIndex)) != -1) {
794 int endIndex = lastIndex + wordSize;
795 offsetList.add(new Integer[] {lastIndex,endIndex} );
796 lastIndex = endIndex;
803 public ArrayList<Integer[]> findWord(String word,int currentSelectStart ,int currentSelectEnd, boolean caseSensitive , boolean wholeWord , boolean useRegexp ) {
804 String fullText = getseletecDocumentLines(currentSelectStart, currentSelectEnd) ;
806 int offset = this.getParagraphElement(currentSelectStart).getStartOffset() ;
808 int wordSize = word.length();;
809 ArrayList<Integer[]> offsetList = new ArrayList<Integer[]>();
811 //If we don't give any word to find
812 if ( (word != null) && !(word.equals("")) ) {
813 // prepare word for each kind of search
815 word = "\\b" + word + "\\b" ;
818 if (useRegexp || wholeWord ){
819 word = "(?i)" + word ;
822 fullText = fullText.toLowerCase();
823 word = word.toLowerCase();
828 //We find matching words ...
829 // ... for regexp or whole words
830 if (useRegexp || wholeWord){
831 Pattern pattern = Pattern.compile(word);
832 Matcher matcher = pattern.matcher(fullText);
834 while (matcher.find()) {
835 offsetList.add(new Integer[] {matcher.start()+offset ,matcher.end()+offset});
837 // ... for other case
839 while ((lastIndex = fullText.indexOf(word, lastIndex)) != -1) {
840 int endIndex = lastIndex + wordSize;
841 offsetList.add(new Integer[] {lastIndex+offset ,endIndex+offset } );
842 lastIndex = endIndex;
849 public int[] readText(int s, int e) {
852 String textLine = "";
854 Vector<Integer> min = new Vector<Integer>();
855 Vector<Integer> max = new Vector<Integer>();
856 int[] interval = new int[2];
858 //We read the document
859 for (int i = 0; i < this.getLength();) {
860 startOffset = this.getParagraphElement(i).getStartOffset();
861 endOffset = this.getParagraphElement(i).getEndOffset();
862 min.add(startOffset);
866 //Get the document line by line
867 textLine = this.getText(startOffset, endOffset - startOffset);
868 } catch (BadLocationException ex) {
869 ex.printStackTrace();
875 //If we only select a part of a line
876 for (int i = 0; i < min.size(); i++) {
877 if (s > min.elementAt(i)) {
878 interval[0] = min.elementAt(i);
881 for (int i = 0; i < max.size(); i++) {
882 if (e > max.elementAt(i)) {
883 interval[1] = max.elementAt(i);
884 interval[1] = interval[1] - 1 ;
891 * Get the next expression matching the search after the caret current position
892 * @param word , the word or regexp to find
893 * @param currentPos, the position where the search start
894 * @param caseSensitive , whether the search is sensitive or not to case
895 * @param wholeWord , whether the search will only look to separate word or not
896 * @param useRegexp , whether the string to search should be interpreted as a regexp or not
898 public int[] findNextWord (String word ,int currentPos, boolean caseSensitive , boolean wholeWord , boolean useRegexp ){
899 String fullText = getFullDocument();
905 if ( (word != null) && (!word.equals("")) ) {
906 // prepare word for each kind of search
908 word = "\\b" + word + "\\b" ;
911 if (useRegexp || wholeWord ){
912 word = "(?i)" + word ;
915 fullText = fullText.toLowerCase();
916 word = word.toLowerCase();
921 //We find matching words ...
922 // ... for regexp or whole words
923 if (useRegexp || wholeWord){
924 Pattern pattern = Pattern.compile(word);
925 Matcher matcher = pattern.matcher(fullText.substring(currentPos));
927 if (matcher.find()) {
928 index = matcher.start()+currentPos;
929 end = matcher.end()+currentPos;
935 // ... for other case
937 index = fullText.indexOf(word,currentPos);
938 end = index + word.length();
942 return new int [] {index , end } ;
945 public int[] findNextWord (String word ,int currentPos,int currentSelectStart ,int currentSelectEnd, boolean caseSensitive , boolean wholeWord , boolean useRegexp ){
947 String fullText = getseletecDocumentLines(currentSelectStart, currentSelectEnd) ;
948 int offset = this.getParagraphElement(currentSelectStart).getStartOffset() ;
949 System.out.println(currentPos) ;
950 currentPos -= offset ;
956 if ( (word != null) && (!word.equals("")) ) {
957 // prepare word for each kind of search
959 word = "\\b" + word + "\\b" ;
962 if (useRegexp || wholeWord ){
963 word = "(?i)" + word ;
966 fullText = fullText.toLowerCase();
967 word = word.toLowerCase();
972 //We find matching words ...
973 // ... for regexp or whole words
974 if (useRegexp || wholeWord){
975 Pattern pattern = Pattern.compile(word);
976 Matcher matcher = pattern.matcher(fullText.substring(currentPos));
978 if (matcher.find()) {
979 index = matcher.start()+currentPos+offset;
980 end = matcher.end()+currentPos+offset;
986 // ... for other case
989 index = fullText.indexOf(word,currentPos);
990 if (index != -1) index += offset ;
991 end = index + word.length();
995 return new int [] {index , end } ;
1001 * Get the previous expression matching the search before the caret current position
1002 * @param word , the word or regexp to find
1003 * @param currentPos, the position where the search start
1004 * @param caseSensitive , whether the search is sensitive or not to case
1005 * @param wholeWord , whether the search will only look to separate word or not
1006 * @param useRegexp , whether the string to search should be interpreted as a regexp or not
1008 public int[] findPreviousWord (String word , int currentPos, boolean caseSensitive , boolean wholeWord , boolean useRegexp ){
1009 String fullText = getFullDocument();
1014 if ( (word != null) && (!word.equals("")) ) {
1016 // prepare word for each kind of search
1018 word = "\\b" + word + "\\b" ;
1020 if (!caseSensitive){
1021 if (useRegexp || wholeWord ){
1022 word = "(?i)" + word ;
1025 fullText = fullText.toLowerCase();
1026 word = word.toLowerCase();
1031 //We find matching words ...
1032 // ... for regexp or whole words
1034 if (useRegexp || wholeWord){
1035 pattern = Pattern.compile(word);
1036 }else{// ... for other case
1037 // we use regexp in both case cause of a nasty bug when you have string like
1038 //121212 and you search "121" forward then backward
1039 pattern = Pattern.compile(word , Pattern.LITERAL );
1042 Matcher matcher = pattern.matcher(fullText.substring(0,currentPos));
1044 boolean found = false ;
1045 while (matcher.find()) {
1046 index = matcher.start();
1047 end = matcher.end();
1058 /*if nothing index and end will both be equal to -1*/
1059 return new int [] {index , end } ;
1065 public int[] findPreviousWord (String word , int currentPos,int currentSelectStart ,int currentSelectEnd, boolean caseSensitive , boolean wholeWord , boolean useRegexp ){
1066 String fullText = getseletecDocumentLines(currentSelectStart, currentSelectEnd) ;
1067 int offset = this.getParagraphElement(currentSelectStart).getStartOffset() ;
1068 System.out.println(currentPos) ;
1069 currentPos -= offset ;
1074 if ( (word != null) && (!word.equals("")) ) {
1076 // prepare word for each kind of search
1078 word = "\\b" + word + "\\b" ;
1080 if (!caseSensitive){
1081 if (useRegexp || wholeWord ){
1082 word = "(?i)" + word ;
1085 fullText = fullText.toLowerCase();
1086 word = word.toLowerCase();
1091 //We find matching words ...
1092 // ... for regexp or whole words
1094 if (useRegexp || wholeWord){
1095 pattern = Pattern.compile(word);
1096 }else{// ... for other case
1097 // we use regexp in both case cause of a nasty bug when you have string like
1098 //121212 and you search "121" forward then backward
1099 pattern = Pattern.compile(word , Pattern.LITERAL );
1102 System.out.println(currentPos) ;
1103 Matcher matcher = pattern.matcher(fullText.substring(0,currentPos));
1105 boolean found = false ;
1106 while (matcher.find()) {
1107 index = matcher.start() + offset;
1108 end = matcher.end() + offset;
1119 /*if nothing index and end will both be equal to -1*/
1120 return new int [] {index , end } ;
1127 * FIND AND REPLACE END
1132 * UTILITARIAN FUNCTIONS START
1135 * Get all Scilab's keywords into a hashtable
1137 public Hashtable<String, String[]> getScilabKeywords() {
1138 //Get all Scilab keywords with SWIG
1139 String[] commands = ScilabKeywords.GetCommandsName();
1140 String[] functions = ScilabKeywords.GetFunctionsName();
1141 String[] macros = ScilabKeywords.GetMacrosName();
1142 //String[] variables = ScilabKeywords.GetVariablesName();
1144 Hashtable<String, String[]> keywords = new Hashtable<String, String[]>();
1146 for (int i = 0; i < commands.length; i++) {
1147 keywords.put("command", commands);
1149 for (int i = 0; i < functions.length; i++) {
1150 keywords.put("function", functions);
1152 for (int i = 0; i < macros.length; i++) {
1153 keywords.put("macro", macros);
1159 * Parse all Scilab keywords
1160 * This function is used for the syntactic colorization
1162 private Vector<Vector<Integer>> parse(String[] bools, String[] commands, String[] comments,
1163 String[] functions, String[] macros, String[] operators, String[] quotations, boolean singleLine, int start, int end) {
1165 Vector<Integer> boolsBoundaries, commandsBoundaries,
1166 commentsBoundaries, functionsBoundaries,
1167 macrosBoundaries, operatorsBoundaries,
1168 quotationsBoundaries;
1170 Vector<Vector<Integer>> boundaries_list = new Vector<Vector<Integer>>();
1172 boolsBoundaries = findBoundaries(bools, singleLine, start, end, null);
1173 commandsBoundaries = findBoundaries(commands, singleLine, start, end, null);
1174 commentsBoundaries = findBoundaries(comments, singleLine, start, end, null);
1175 functionsBoundaries = findBoundaries(functions, singleLine, start, end, null);
1176 macrosBoundaries = findBoundaries(macros, singleLine, start, end, null);
1177 operatorsBoundaries = findBoundaries(operators, singleLine, start, end, null);
1178 quotationsBoundaries = findBoundaries(quotations, singleLine, start, end, null);
1181 boundaries_list = organizeBoundaries(boolsBoundaries, commandsBoundaries, commentsBoundaries, functionsBoundaries,
1182 macrosBoundaries, operatorsBoundaries, quotationsBoundaries);
1184 return boundaries_list;
1188 * Get start & end position for each keywords
1189 * String[] keyword is a type of keywords(ex: operators, commands, macros..)
1190 * String text is where we make the search,
1191 * if text is null we apply the research to the entire document
1193 private Vector<Integer> findBoundaries(String[] keyword, boolean singleLine, int start, int end, String text) {
1196 Matcher matcher = null;
1197 Vector<Integer> bound = new Vector<Integer>();
1199 for(int i = 0 ; i < keyword.length ; i++) {
1200 pattern = Pattern.compile(keyword[i], Pattern.DOTALL);
1202 if (singleLine && text == null) {
1203 matcher = pattern.matcher(this.getText(start, end - start));
1204 while(matcher.find()){
1205 //System.err.println("Match Found : "+(matcher.start())+","+(matcher.end()/*-matcher.start()*/));
1206 bound.add(new Integer(matcher.start() + start));
1207 bound.add(new Integer(matcher.end() + start));
1212 matcher = pattern.matcher(text);
1214 matcher = pattern.matcher(this.getText(0, this.getLength()));
1217 while(matcher.find()){
1218 //System.err.println("Match Found : "+(matcher.start())+","+(matcher.end()/*-matcher.start()*/));
1219 bound.add(new Integer(matcher.start()));
1220 bound.add(new Integer(matcher.end()));
1223 } catch (BadLocationException e) {
1224 e.printStackTrace();
1231 * When we have all boundaries for each type of keywords
1232 * we filter 'bad' boundaries
1233 * ex: if we have quotations into comments (and the opposite), keywords into quotations or comments
1235 private Vector<Vector<Integer>> organizeBoundaries(Vector<Integer> boolsBoundaries, Vector<Integer> commandsBoundaries,
1236 Vector<Integer> commentsBoundaries, Vector<Integer> functionsBoundaries,
1237 Vector<Integer> macrosBoundaries, Vector<Integer> operatorsBoundaries,
1238 Vector<Integer> quotationsBoundaries) {
1240 Vector<Integer> tmp_comm_and_quot = new Vector<Integer>();
1241 Vector<Vector<Integer>> vector_list = new Vector<Vector<Integer>>();
1243 // Remove comments which are into quotations
1244 commentsBoundaries = startNotIn(commentsBoundaries, quotationsBoundaries);
1245 // Remove quotations which are into comments
1246 quotationsBoundaries = startNotIn(quotationsBoundaries, commentsBoundaries);
1248 // Union of comments & quotations to remove keywords
1249 tmp_comm_and_quot.addAll(commentsBoundaries);
1250 tmp_comm_and_quot.addAll(quotationsBoundaries);
1252 // Remove keywords which are into comments & quotations
1253 boolsBoundaries = strictlyNotIn(boolsBoundaries, tmp_comm_and_quot);
1254 commandsBoundaries = strictlyNotIn(commandsBoundaries, tmp_comm_and_quot);
1255 functionsBoundaries = strictlyNotIn(functionsBoundaries, tmp_comm_and_quot);
1256 macrosBoundaries = strictlyNotIn(macrosBoundaries, tmp_comm_and_quot);
1257 operatorsBoundaries = strictlyNotIn(operatorsBoundaries, tmp_comm_and_quot);
1259 vector_list.add(boolsBoundaries);
1260 vector_list.add(commandsBoundaries);
1261 vector_list.add(commentsBoundaries);
1262 vector_list.add(functionsBoundaries);
1263 vector_list.add(macrosBoundaries);
1264 vector_list.add(operatorsBoundaries);
1265 vector_list.add(quotationsBoundaries);
1270 private Vector<Integer> strictlyNotIn(Vector<Integer> v1, Vector<Integer> v2) {
1276 Vector<Integer> vector_strictlyNotIn = new Vector<Integer>();
1278 // Remove interval from v1 which are include in interval of v2
1279 for(int i=0; i < v1.size(); i=i+2) {
1280 boolean dropMe = false;
1281 v1_start = v1.elementAt(i);
1282 v1_end = v1.elementAt(i+1);
1284 for(int j=0; j < v2.size(); j=j+2) {
1285 v2_start = v2.elementAt(j);
1286 v2_end = v2.elementAt(j+1);
1288 if(((v1_start >= v2_start) && (v1_start <= v2_end)) && ((v1_end >= v2_start) && (v1_end <= v2_end))) {
1293 vector_strictlyNotIn.addElement(v1.elementAt(i));
1294 vector_strictlyNotIn.addElement(v1.elementAt(i+1));
1297 //System.out.println("vector_strictlyNotIn"+vector_strictlyNotIn);
1299 return vector_strictlyNotIn;
1302 private Vector<Integer> startNotIn(Vector<Integer> v1, Vector<Integer> v2) {
1306 Vector<Integer> vector_startNotIn = new Vector<Integer>();
1308 for(int i=0; i < v1.size(); i=i+2) {
1309 boolean dropMe = false;
1310 v1_start = v1.elementAt(i);
1312 for(int j=0; j < v2.size(); j=j+2) {
1313 v2_start = v2.elementAt(j);
1314 v2_end = v2.elementAt(j+1);
1316 if(((v1_start >= v2_start) && (v1_start <= v2_end))) {
1321 vector_startNotIn.addElement(v1.elementAt(i));
1322 vector_startNotIn.addElement(v1.elementAt(i+1));
1325 //System.out.println("vector_startNotIn"+vector_startNotIn);
1327 return vector_startNotIn;
1330 * UTILITARIAN FUNCTIONS END
1333 private final void DEBUG(String msg) {
1334 System.err.println("[DEBUG] "+msg);
1336 public void disableUpdaters() {
1337 updaterDisabled = true;
1340 public String getFullDocument() {
1343 String textLine = "";
1346 //We read the document and put the document into the String text
1347 for (int i = 0; i < this.getLength();) {
1348 startOffset = this.getParagraphElement(i).getStartOffset();
1349 endOffset = this.getParagraphElement(i).getEndOffset();
1352 //Get the document line by line
1353 textLine = this.getText(startOffset, endOffset - startOffset);
1354 } catch (BadLocationException ex) {
1355 ex.printStackTrace();
1363 public String getseletecDocumentLines(int start , int end ) {
1369 startOffset = this.getParagraphElement(start).getStartOffset();
1370 endOffset = this.getParagraphElement(end).getEndOffset();
1371 //We read the document and put the document into the String text
1374 //Get the document line by line
1375 text = this.getText(startOffset, endOffset - startOffset);
1376 } catch (BadLocationException ex) {
1377 ex.printStackTrace();
1384 public void enableUpdaters() {
1385 updaterDisabled = false;
1388 public void insertUpdate(DocumentEvent e) {
1390 EventType = e.getType().toString();
1391 //Element[] pouet = e.getChange( this.getParagraphElement(editor.getTextPane().getCaretPosition())).getChildrenAdded();
1394 //System.err.println("--- Calling insertUpdate");
1395 if (!updaterDisabled) {
1396 SwingUtilities.invokeLater(new Runnable() {
1401 IndentAction.getXpadEditor();
1402 editor = getEditor();
1403 int caretPosition = editor.getTextPane().getCaretPosition();
1406 if (editor.getTextPane().getText(caretPosition-1, 1).equals("\n")) {
1407 System.out.println("------------ SAUTE de LIGNE ------------");
1410 } catch (BadLocationException e) {
1411 e.printStackTrace();
1418 setSingleLine(true);
1419 ColorizeAction.getXpadEditor();
1420 editor = getEditor();
1422 // Get the current line (position of the caret)
1423 int caretPosition = editor.getTextPane().getCaretPosition();
1424 currentLine = editor.getTextPane().getStyledDocument().getDefaultRootElement().getElementIndex(caretPosition);
1426 // Get current line's start & end offsets
1427 lineStartPosition = editor.getTextPane().getStyledDocument().getParagraphElement(caretPosition).getStartOffset();
1428 lineEndPosition = editor.getTextPane().getStyledDocument().getParagraphElement(caretPosition).getEndOffset()-1;
1430 // If we add a line (by pressing return)
1431 if (lineStartPosition == lineEndPosition) {
1432 lineStartPosition = lineStartPosition + lineEndPosition;
1433 lineEndPosition = lineEndPosition + lineEndPosition;
1436 if (lineStartPosition != lineEndPosition) {
1437 colorizeSingleLine(lineStartPosition, lineEndPosition);
1439 setSingleLine(false);
1445 public void removeUpdate(DocumentEvent e) {
1447 EventType = e.getType().toString() ;
1448 //System.err.println("--- Calling ScilabStyleDocument.removeUpdate");
1449 if (!updaterDisabled) {
1450 SwingUtilities.invokeLater(new Runnable() {
1455 // IndentAction.getXpadEditor();
1456 // editor = getEditor();
1457 // int caretPosition = editor.getTextPane().getCaretPosition();
1460 // if (!(caretPosition == 0)) {
1461 // caretPosition = caretPosition -1;
1463 // if (editor.getTextPane().getText(caretPosition, 1).equals("\n")) {
1464 // System.out.println("JE SAUTE UNE LIGNE");
1466 // // Get start & end offsets of the selected text
1467 // int selection_start = editor.getTextPane().getSelectionStart();
1468 // int selection_end = editor.getTextPane().getSelectionEnd();
1470 // // Get start offsets of the first selected line & end offsets of the last selected line
1471 // lineStartPosition = editor.getTextPane().getStyledDocument().getParagraphElement(selection_start).getStartOffset();
1472 // lineEndPosition = editor.getTextPane().getStyledDocument().getParagraphElement(selection_end).getEndOffset()-1;
1476 // } catch (BadLocationException e) {
1477 // e.printStackTrace();
1482 setSingleLine(true);
1483 ColorizeAction.getXpadEditor();
1484 editor = getEditor();
1487 // Get the current line (position of the caret)
1488 int caretPosition = editor.getTextPane().getCaretPosition();
1489 currentLine = editor.getTextPane().getStyledDocument().getDefaultRootElement().getElementIndex(caretPosition);
1491 // Get current line's start & end offsets
1492 lineStartPosition = editor.getTextPane().getStyledDocument().getParagraphElement(caretPosition).getStartOffset();
1493 lineEndPosition = editor.getTextPane().getStyledDocument().getParagraphElement(caretPosition).getEndOffset()-1;
1495 // If we add a line (by pressing return)
1496 if (lineStartPosition == lineEndPosition) {
1497 lineStartPosition = lineStartPosition + lineEndPosition;
1498 lineEndPosition = lineEndPosition + lineEndPosition;
1501 if (lineStartPosition != lineEndPosition) {
1502 colorizeSingleLine(lineStartPosition, lineEndPosition);
1504 setSingleLine(false);
1511 public void changedUpdate(DocumentEvent arg0) {
1513 EventType = arg0.getType().toString() ;
1514 // TODO Auto-generated method stub
1517 public void setAutoIndent(boolean b) {
1518 //DEBUG("setAutoIndent("+b+")");
1521 public boolean getAutoIndent() {
1522 //DEBUG("getAutoIndent("+autoIndent+")");
1525 public UndoManager getUndoManager() {
1530 public boolean isContentModified(){
1531 return contentModified ;
1534 public void setContentModified(boolean contentModified){
1535 this.contentModified = contentModified ;
1539 public boolean isSingleLine() {
1543 public void setSingleLine(boolean singleLine) {
1544 this.singleLine = singleLine;
1547 public int getLineToColor() {
1551 public void setLineToColor(int lineToColor) {
1552 this.currentLine = lineToColor;
1556 public int getLineEndPosition() {
1557 return lineEndPosition;
1560 public void setLineEndPosition(int lineEndPosition) {
1561 this.lineEndPosition = lineEndPosition;
1564 public int getLineStartPosition() {
1565 return lineStartPosition;
1568 public void setLineStartPosition(int lineStartPosition) {
1569 this.lineStartPosition = lineStartPosition;
1575 public Xpad getEditor() {
1579 public void setEditor(Xpad editor) {
1580 this.editor = editor;