Package edu.mit.csail.sdg.alloy4

Source Code of edu.mit.csail.sdg.alloy4.OurSyntaxDocument

/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package edu.mit.csail.sdg.alloy4;

import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;
import static edu.mit.csail.sdg.alloy4.OurConsole.style;

/** Graphical syntax-highlighting StyledDocument.
*
* <p><b>Thread Safety:</b> Can be called only by the AWT event thread
*/

class OurSyntaxDocument extends DefaultStyledDocument {

   /** This ensures the class can be serialized reliably. */
   private static final long serialVersionUID = 0;

   /** The "comment mode" at the start of each line (0 = no comment) (1 = block comment) (2 = javadoc comment) (-1 = unknown) */
   private final List<Integer> comments = new ArrayList<Integer>();

   /** Whether syntax highlighting is currently enabled or not. */
   private boolean enabled = true;

   /** The current font name is. */
   private String font = "Monospaced";

   /** The current font size. */
   private int fontSize = 14;

   /** The current tab size. */
   private int tabSize = 4;

   /** The list of font+color styles (eg. regular text, symbols, keywords, comments, etc). */
   private final List<MutableAttributeSet> all = new ArrayList<MutableAttributeSet>();

   /** The character style for regular text. */
   private final MutableAttributeSet styleNormal  = style(font, fontSize, false, Color.BLACK, 0);          { all.add(styleNormal); }

   /** The character style for symbols. */
   private final MutableAttributeSet styleSymbol  = style(font, fontSize, true, Color.BLACK, 0);           { all.add(styleSymbol); }

   /** The character style for integer constants. */
   private final MutableAttributeSet styleNumber  = style(font, fontSize, true, new Color(0xA80A0A), 0);   { all.add(styleNumber); }

   /** The character style for keywords. */
   private final MutableAttributeSet styleKeyword = style(font, fontSize, true, new Color(0x1E1EA8), 0);   { all.add(styleKeyword); }

   /** The character style for string literals. */
   private final MutableAttributeSet styleString  = style(font, fontSize, false, new Color(0xA80AA8), 0){ all.add(styleString); }

   /** The character style for up-to-end-of-line-style comment. */
   private final MutableAttributeSet styleComment = style(font, fontSize, false, new Color(0x0A940A), 0){ all.add(styleComment); }

   /** The character style for non-javadoc-style block comment. */
   private final MutableAttributeSet styleBlock   = style(font, fontSize, false, new Color(0x0A940A), 0){ all.add(styleBlock); }

   /** The character style for javadoc-style block comment. */
   private final MutableAttributeSet styleJavadoc = style(font, fontSize, true, new Color(0x0A940A), 0);   { all.add(styleJavadoc); }

   /** The paragraph style for indentation. */
   private final MutableAttributeSet tabset = new SimpleAttributeSet();

   /** This stores the currently recognized set of reserved keywords. */
   private static final String[] keywords = new String[] {"abstract", "all", "and", "as", "assert", "but", "check", "disj",
      "disjoint", "else", "enum", "exactly", "exh", "exhaustive", "expect", "extends", "fact", "for", "fun", "iden",
      "iff", "implies", "in", "Int", "int", "let", "lone", "module", "no", "none", "not", "one", "open", "or", "part",
      "partition", "pred", "private", "run", "seq", "set", "sig", "some", "String", "sum", "this", "univ"
   };

   /** Returns true if array[start .. start+len-1] matches one of the reserved keyword. */
   private static final boolean do_keyword(String array, int start, int len) {
      if (len >= 2 && len <= 10) for(int i = keywords.length - 1; i >= 0; i--) {
         String str = keywords[i];
         if (str.length()==len) for(int j=0; ;j++) if (j==len) return true; else if (str.charAt(j) != array.charAt(start+j)) break;
      }
      return false;
   }

   /** Returns true if "c" can be in the start or middle or end of an identifier. */
   private static final boolean do_iden(char c) {
      return (c>='A' && c<='Z') || (c>='a' && c<='z') || c=='$' || (c>='0' && c<='9') || c=='_' || c=='\'' || c=='\"';
   }

   /** Constructor. */
   public OurSyntaxDocument(String fontName, int fontSize) {
      putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n");
      tabSize++;
      do_setFont(fontName, fontSize, tabSize - 1); // assigns the given font, and also forces recomputation of the tab size
   }

   /** Enables or disables syntax highlighting. */
   public final void do_enableSyntax (boolean flag) {
      if (enabled == flag) return; else { enabled = flag;  comments.clear(); }
      if (flag) do_reapplyAll(); else setCharacterAttributes(0, getLength(), styleNormal, false);
   }

   /** Return the number of lines represented by the current text (where partial line counts as a line).
    * <p> For example: count("")==1, count("x")==1, count("x\n")==2, and count("x\ny")==2
    */
   public final int do_getLineCount() {
      String txt = toString();
      for(int n=txt.length(), ans=1, i=0; ; i++) if (i>=n) return ans; else if (txt.charAt(i)=='\n') ans++;
   }

   /** Return the starting offset of the given line (If "line" argument is too large, it will return the last line's starting offset)
    * <p> For example: given "ab\ncd\n", start(0)==0, start(1)==3, start(2...)==6.  Same thing when given "ab\ncd\ne".
    */
   public final int do_getLineStartOffset(int line) {
      String txt = toString();
      for(int n=txt.length(), ans=0, i=0, y=0; ; i++) if (i>=n || y>=line) return ans; else if (txt.charAt(i)=='\n') {ans=i+1; y++;}
   }

   /** Return the line number that the offset is in (If "offset" argument is too large, it will just return do_getLineCount()-1).
    * <p> For example: given "ab\ncd\n", offset(0..2)==0, offset(3..5)==1, offset(6..)==2.  Same thing when given "ab\ncd\ne".
    */
   public final int do_getLineOfOffset(int offset) {
      String txt = toString();
      for(int n=txt.length(), ans=0, i=0; ; i++) if (i>=n || i>=offset) return ans; else if (txt.charAt(i)=='\n') ans++;
   }

   /** This method is called by Swing to insert a String into this document.
    * We intentionally ignore "attr" and instead use our own coloring.
    */
   @Override public void insertString(int offset, String string, AttributeSet attr) throws BadLocationException {
      if (string.indexOf('\r')>=0) string = Util.convertLineBreak(string); // we don't want '\r'
      if (!enabled) { super.insertString(offset, string, styleNormal); return; }
      int startLine = do_getLineOfOffset(offset);
      for(int i = 0; i < string.length(); i++) { // For each inserted '\n' we need to shift the values in "comments" array down
         if (string.charAt(i)=='\n') { if (startLine < comments.size()-1) comments.add(startLine+1, -1); }
      }
      super.insertString(offset, string, styleNormal);
      try { do_update(startLine); } catch(Exception ex) { comments.clear(); }
   }

   /** This method is called by Swing to delete text from this document. */
   @Override public void remove(int offset, int length) throws BadLocationException {
      if (!enabled) { super.remove(offset, length); return; }
      int i = 0, startLine = do_getLineOfOffset(offset);
      for(String oldText = toString(); i<length; i++) { // For each deleted '\n' we need to shift the values in "comments" array up
         if (oldText.charAt(offset+i)=='\n') if (startLine < comments.size()-1) comments.remove(startLine+1);
      }
      super.remove(offset, length);
      try { do_update(startLine); } catch(Exception ex) { comments.clear(); }
   }

   /** This method is called by Swing to replace text in this document. */
   @Override public void replace(int offset, int length, String string, AttributeSet attrs) throws BadLocationException {
      if (length > 0) this.remove(offset, length);
      if (string != null && string.length() > 0) this.insertString(offset, string, styleNormal);
   }

   /** Reapply styles assuming the given line has just been modified */
   private final void do_update(int line) throws BadLocationException  {
      String content = toString();
      int lineCount = do_getLineCount();
      while(line>0 && (line>=comments.size() || comments.get(line)<0)) line--; // "-1" in comments array are always contiguous
      int comment = do_reapply(line==0 ? 0 : comments.get(line), content, line);
      for (line++; line < lineCount; line++) { // update each subsequent line until it already starts with its expected comment mode
         if (line < comments.size() && comments.get(line) == comment) break; else comment = do_reapply(comment, content, line);
      }
   }

   /** Re-color the given line assuming it starts with a given comment mode, then return the comment mode for start of next line. */
   private final int do_reapply(int comment, final String txt, final int line) {
      while (line >= comments.size()) comments.add(-1); // enlarge array if needed
      comments.set(line, comment);                      // record the fact that this line starts with the given comment mode
      for(int n = txt.length(), i = do_getLineStartOffset(line); i < n;) {
         final int oldi = i;
         final char c = txt.charAt(i);
         if (c=='\n') break;
         if (comment==0 && c=='/' && i<n-3 && txt.charAt(i+1)=='*' && txt.charAt(i+2)=='*' && txt.charAt(i+3)!='/') comment = 2;
         if (comment==0 && c=='/' && i==n-3 && txt.charAt(i+1)=='*' && txt.charAt(i+2)=='*') comment = 2;
         if (comment==0 && c=='/' && i<n-1 && txt.charAt(i+1)=='*') { comment = 1; i = i + 2; }
         if (comment>0) {
            AttributeSet style = (comment==1 ? styleBlock : styleJavadoc);
            while(i<n && txt.charAt(i)!='\n' && (txt.charAt(i)!='*' || i+1==n || txt.charAt(i+1)!='/')) i = i + 1;
            if (i<n-1 && txt.charAt(i)=='*' && txt.charAt(i+1)=='/') { i = i + 2; comment = 0; }
            setCharacterAttributes(oldi, i-oldi, style, false);
         } else if ((c=='/' || c=='-') && i<n-1 && txt.charAt(i+1)==c) {
            i = txt.indexOf('\n', i);
            setCharacterAttributes(oldi, i<0 ? (n-oldi) : (i-oldi), styleComment, false);
            break;
         } else if (c=='\"') {
            for(i++; i<n; i++) {
               if (txt.charAt(i)=='\n') break;
               if (txt.charAt(i)=='\"') {i++; break;}
               if (txt.charAt(i)=='\\' && i+1<n && txt.charAt(i+1)!='\n') i++;
            }
            setCharacterAttributes(oldi, i-oldi, styleString, false);
         } else if (do_iden(c)) {
            for(i++; i<n && do_iden(txt.charAt(i)); i++) { }
            AttributeSet style = (c>='0' && c<='9') ? styleNumber : (do_keyword(txt, oldi, i-oldi) ? styleKeyword : styleNormal);
            setCharacterAttributes(oldi, i-oldi, style, false);
         } else {
            for(i++; i<n && !do_iden(txt.charAt(i)) && txt.charAt(i)!='\n' && txt.charAt(i)!='-' && txt.charAt(i)!='/'; i++) { }
            setCharacterAttributes(oldi, i-oldi, styleSymbol, false);
         }
      }
      return comment;
   }

   /** Reapply the appropriate style to the entire document. */
   private final void do_reapplyAll() {
      setCharacterAttributes(0, getLength(), styleNormal, true);
      comments.clear();
      String content = toString();
      for(int comment = 0, i = 0, n = do_getLineCount(); i < n; i++comment = do_reapply(comment, content, i);
   }

   /** Changes the font and tabsize for the document. */
   public final void do_setFont(String fontName, int fontSize, int tabSize) {
      if (tabSize < 1) tabSize = 1; else if (tabSize > 100) tabSize = 100;
      if (fontName.equals(this.font) && fontSize == this.fontSize && tabSize == this.tabSize) return;
      this.font = fontName;
      this.fontSize = fontSize;
      this.tabSize = tabSize;
      for(MutableAttributeSet s: all) { StyleConstants.setFontFamily(s, fontName);  StyleConstants.setFontSize(s, fontSize); }
      do_reapplyAll();
      BufferedImage im = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB); // this is used to derive the tab width
      int gap = tabSize * im.createGraphics().getFontMetrics(new Font(fontName, Font.PLAIN, fontSize)).charWidth('X');
      TabStop[] pos = new TabStop[100];
      for(int i=0; i<100; i++) { pos[i] = new TabStop(i*gap + gap); }
      StyleConstants.setTabSet(tabset, new TabSet(pos));
      setParagraphAttributes(0, getLength(), tabset, false);
   }

   /** Overriden to return the full text of the document.
    * @return the entire text
    */
   @Override public String toString() {
      try { return getText(0, getLength()); } catch(BadLocationException ex) { return ""; }
   }
}
TOP

Related Classes of edu.mit.csail.sdg.alloy4.OurSyntaxDocument

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.