Changeset 1444


Ignore:
Timestamp:
May 10, 2012, 10:12:52 PM (6 years ago)
Author:
joerg
Message:

improved bibtex support: alt+enter on an author or value to extract @string{...}

Location:
trunk
Files:
2 added
12 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/data/styles/user.xml

    r1422 r1444  
    2121  <element name="parser_stop" style="bold,italic" foreground="db8717"/>
    2222  <element name="error" style="plain" foreground="ff0000"/>
     23  <element name="baderror" style="plain" background="ff9988"/>
    2324  <element name="begin" style="bold" foreground="000080"/>
    2425  <element name="section" style="bold" foreground="f00000"/>
  • trunk/scripting/haskell/Trees.hs

    r1407 r1444  
    104104      zip5 _ _ _ _ _ = []
    105105  in zip5
    106       ("" : nodes)
     106      (head nodes : nodes)
    107107      (directions $ (-1):depths)
    108108      nodes
     
    131131   then south_east c root ++ " -- "
    132132   else east c root ++ " -- ") ++
    133   north_east c root ++ " -- " ++ north c root ++ " -- " ++
     133  north_east c root ++ " -- " ++ north c root ++ " -- " ++ 
    134134  -- remaining path
    135135  renderHighlight_ c tree (up_down tree $ nodes highlight)
  • trunk/src/jlatexeditor/SCEManager.java

    r1431 r1444  
    22
    33import de.endrullis.utils.LazyVal;
     4import jlatexeditor.bib.BibAssistant;
    45import jlatexeditor.bib.BibCodeCompletion;
    56import jlatexeditor.bib.BibSyntaxHighlighting;
     
    268269    CombinedCodeAssistant codeAssistant = new CombinedCodeAssistant();
    269270    try {
     271      codeAssistant.addAssistant(new BibAssistant());
    270272      codeAssistant.addAssistant(new SpellCheckSuggester(createSpellChecker()));
    271273    } catch (Exception ignored) {
  • trunk/src/jlatexeditor/bib/BibAssistant.java

    r1438 r1444  
    1 package jlatexeditor.codehelper;
    2 
    3 import de.endrullis.utils.StringUtils;
    4 import jlatexeditor.Doc;
    5 import jlatexeditor.SCEManager;
    6 import jlatexeditor.tools.SVN;
     1package jlatexeditor.bib;
     2
     3import jlatexeditor.JLatexEditorJFrame;
     4import org.jetbrains.annotations.Nullable;
    75import sce.codehelper.CodeAssistant;
    86import sce.codehelper.PatternPair;
    97import sce.codehelper.SCEPopup;
    108import sce.codehelper.WordWithPos;
    11 import sce.component.SCEPane;
     9import sce.component.*;
     10import sce.syntaxhighlighting.ParserStateStack;
    1211
    1312import javax.swing.*;
    14 import java.io.File;
    15 import java.io.IOException;
     13import javax.swing.event.DocumentEvent;
     14import javax.swing.event.DocumentListener;
     15import java.awt.*;
    1616import java.util.ArrayList;
     17import java.util.Collections;
     18import java.util.HashSet;
    1719import java.util.List;
    1820
    1921/**
    20  * Suggests to create a file.
     22 * Assists with bibtex files.
    2123 *
    22  * @author Stefan Endrullis &lt;stefan@endrullis.de&gt;
     24 * @author Joerg Endrullis &lt;joerg@endrullis.de&gt;
    2325 */
    24 public class FileCreationSuggester implements CodeAssistant, SCEPopup.ItemHandler {
    25   private PatternPair parameterPattern = new PatternPair("\\\\(input|include|lstinputlisting)(?:\\[[^\\]]*\\])?\\{([^\\{]*)", "([^\\}]*)\\}");
    26 
    27   public FileCreationSuggester() {
     26public class BibAssistant implements CodeAssistant, SCEPopup.ItemHandler {
     27  PatternPair authorPattern = new PatternPair("(?:^| and )(?:(?! and ) )*((?:(?! and ).)*?)", true, "(.*?)(?:$| and$| and )");
     28
     29  public BibAssistant() {
    2830  }
    2931
    3032  public boolean assistAt(SCEPane pane) {
    31     List<WordWithPos> words = parameterPattern.find(pane);
    32     if (words != null) {
    33       WordWithPos word = words.get(1);
    34 
    35       Doc resource = SCEManager.getInstance().getMainEditor().getResource();
    36       if (resource instanceof Doc.FileDoc) {
    37         Doc.FileDoc fileDoc = (Doc.FileDoc) resource;
    38         String filename = word.word;
    39 
    40         // add .tex if no extension given
    41         String lastPart = StringUtils.stringAfter(filename, "/", 'l').getOrElse(filename);
    42         if (!lastPart.contains(".")) {
    43           filename += ".tex";
    44         }
    45 
    46         try {
    47           File file;
    48 
    49           // absolute or relative path?
    50           if (filename.startsWith("/")) {
    51             file = new File(filename);
    52           } else {
    53             String dirPath = fileDoc.getFile().getParentFile().getCanonicalPath();
    54             file = new File(dirPath + "/" + filename);
    55           }
    56 
    57           // if file does not exists
    58           if (!file.exists()) {
    59             List<Object> list = new ArrayList<Object>();
    60             list.add(new FileCreationAction(filename, file));
    61 
    62             // open popup
    63             pane.getPopup().openPopup(list, this);
    64             return true;
    65           }
    66         } catch (IOException e) {
    67           e.printStackTrace();
    68         }
    69       }
    70     }
    71 
    72     return false;
     33    SCEDocument document = pane.getDocument();
     34    SCEDocumentRow[] rows = document.getRowsModel().getRows();
     35    int row = pane.getCaret().getRow();
     36    int column = pane.getCaret().getColumn();
     37
     38    ParserStateStack stateStack = BibSyntaxHighlighting.parseRow(rows[row], column, document);
     39    BibParserState state = (BibParserState) stateStack.peek();
     40
     41    if(column == 0 && state.getState() == BibParserState.STATE_NOTHING) {
     42      // refactor the whole bib
     43      return false;
     44    }
     45
     46    if(state.getState() != BibParserState.STATE_NOTHING) {
     47      BibEntry entry = state.getEntry();
     48
     49      for(BibKeyValuePair keyValue : entry.getAllParameters().values()) {
     50        for(WordWithPos value : keyValue.getValues()) {
     51          if(value.contains(row, column)) {
     52            String key = keyValue.getKey().word.toLowerCase();
     53
     54            // selection
     55            SCEDocumentPosition selectionStart = document.getSelectionStart();
     56            SCEDocumentPosition selectionEnd = document.getSelectionEnd();
     57            if(document.hasSelection()
     58                    && !selectionStart.equals(selectionEnd)
     59                    && value.contains(selectionStart.getRow(), selectionStart.getColumn())
     60                    && value.contains(selectionEnd.getRow(), selectionEnd.getColumn())) {
     61
     62              popup(pane, document, new WordWithPos(document.getSelectedText(), selectionStart, selectionEnd), "");
     63              return true;
     64            }
     65
     66            // author
     67            if(key.equals("author")) {
     68              List<WordWithPos> params = authorPattern.find(pane, BibKeyValuePair.getInnerStart(value), BibKeyValuePair.getInnerEnd(value));
     69              if(params != null) {
     70                WordWithPos name = params.get(0);
     71                String nameKey = getAuthorString(name.word);
     72
     73                popup(pane, document, name, nameKey);
     74                return true;
     75              }
     76            }
     77
     78            // other values
     79            SCEDocumentPosition start;
     80            SCEDocumentPosition end;
     81            if(value.word.startsWith("\"") || value.word.startsWith("{")) {
     82              start = new SCEDocumentPosition(value.getStartPos().getRow(), value.getStartPos().getColumn()+1);
     83              end = new SCEDocumentPosition(value.getEndPos().getRow(), value.getEndPos().getColumn()-1);
     84            } else {
     85              start = new SCEDocumentPosition(value.getStartPos().getRow(), value.getStartPos().getColumn());
     86              end = new SCEDocumentPosition(value.getEndPos().getRow(), value.getEndPos().getColumn());
     87            }
     88            popup(pane, document, new WordWithPos(document.getText(start, end), start, end), "");
     89            return true;
     90          }
     91        }
     92      }
     93    }
     94
     95    return false;
    7396  }
    7497
     98  private void popup(SCEPane pane, SCEDocument document, WordWithPos word, String key) {
     99    document.setSelectionRange(word.getStartPos(), word.getEndPos(), true);
     100    pane.repaint();
     101
     102    // find similar string
     103    ArrayList<WeightedElement<BibEntry>> weightedEntries = new ArrayList<WeightedElement<BibEntry>>();
     104
     105    ArrayList<BibEntry> stringEntries = getEntries(document, "string");
     106    for(BibEntry stringEntry : stringEntries) {
     107      if(stringEntry.getName().isEmpty()) continue;
     108      String stringValue = stringEntry.getAllParameters().get(stringEntry.getName()).getValuesString();
     109
     110      int common = lcs(word.word, stringValue);
     111      weightedEntries.add(new WeightedElement<BibEntry>(common, stringEntry));
     112    }
     113
     114    Collections.sort(weightedEntries);
     115
     116    List<Object> list = new ArrayList<Object>();
     117    list.add(new CreateStringAction(word.word, key, pane));
     118
     119    for(int itemNr = 0; itemNr < 3; itemNr++) {
     120      if(weightedEntries.isEmpty()) break;
     121      BibEntry entry = weightedEntries.remove(weightedEntries.size()-1).element;
     122      list.add(new ReplaceByAction(word.word, entry.getName(), entry.getAllParameters().get(entry.getName()).getValuesString(), pane));
     123    }
     124
     125    // open popup
     126    pane.getPopup().openPopup(list, this);
     127  }
     128
     129  private ArrayList<BibEntry> getEntries(SCEDocument document, @Nullable String type) {
     130    ArrayList<BibEntry> entries = new ArrayList<BibEntry>();
     131
     132    SCEDocumentRow[] rows = document.getRowsModel().getRows();
     133
     134    BibParserState state = (BibParserState) rows[document.getRowsModel().getRowsCount()-1].parserStateStack.peek();
     135    int entriesCount = state.getEntryNr();
     136    for(int entryNr = 0; entryNr < entriesCount; entryNr++) {
     137      BibEntry entry = state.getEntryByNr().get(entryNr);
     138      if(type != null && !entry.getType().equalsIgnoreCase(type)) continue;
     139      entries.add(entry);
     140    }
     141
     142    return entries;
     143  }
     144
     145  private String getAuthorString(String name) {
     146    name = name.trim().toLowerCase();
     147    name = name.replaceAll("[^\\w\\d\\., ]", "");
     148    name = name.replaceAll(" +"," ");
     149
     150    String firstName = "", lastName = "";
     151
     152    int comma = name.indexOf(',');
     153    if(comma >= 0) {
     154      lastName = name.substring(0, comma);
     155      firstName = name.substring(comma+1);
     156    } else {
     157      String split[] = name.split("[ ](?=[^ ]*$)");
     158      if(split.length == 1) {
     159        lastName = split[0];
     160      } else {
     161        firstName = split[0];
     162        lastName = split[1];
     163      }
     164    }
     165
     166    lastName = lastName.replaceAll(" ","");
     167    lastName = lastName.replaceAll("\\W","");
     168    firstName = firstName.replaceAll("(\\w)\\w*", "$1");
     169    firstName = firstName.replaceAll("\\W","");
     170
     171    return lastName + "." + firstName;
     172  }
     173
     174  /**
     175   * Longest common subsequence: http://introcs.cs.princeton.edu/java/96optimization/.
     176   */
     177  private int lcs(String x, String y) {
     178    int xlength = x.length();
     179    int ylength = y.length();
     180
     181    int[][] opt = new int[xlength+1][ylength+1];
     182
     183    for (int i = xlength-1; i >= 0; i--) {
     184      for (int j = ylength-1; j >= 0; j--) {
     185        if (x.charAt(i) == y.charAt(j))
     186          opt[i][j] = opt[i+1][j+1] + 1;
     187        else
     188          opt[i][j] = Math.max(opt[i+1][j], opt[i][j+1]);
     189      }
     190    }
     191
     192    int length = 0;
     193    int i = 0, j = 0;
     194    while(i < xlength && j < ylength) {
     195      if (x.charAt(i) == y.charAt(j)) {
     196        length++;
     197        i++;
     198        j++;
     199      }
     200      else if (opt[i+1][j] >= opt[i][j+1]) i++;
     201      else                                 j++;
     202    }
     203
     204    return length;
     205  }
     206
     207  private String oneLine(String text) {
     208    text = text.replace('\n', ' ');
     209    text = text.replaceAll(" +", " ");
     210    return text;
     211  }
     212
     213  private void replaceAll(SCEDocument document, String search, String replaceKey) {
     214    ArrayList<BibEntry> entries = getEntries(document, null);
     215    for(BibEntry entry : entries) {
     216      for(BibKeyValuePair keyValues : entry.getAllParameters().values()) {
     217        boolean oneLine = keyValues.getKey().word.equalsIgnoreCase("author");
     218        for(WordWithPos value : keyValues.getValues()) {
     219          if(!value.word.startsWith("\"") && !value.word.startsWith("{")) continue;
     220
     221          replaceIn(document, value, oneLine, search, replaceKey);
     222        }
     223      }
     224    }
     225  }
     226
     227  private void replaceIn(SCEDocument document, WordWithPos value, boolean oneLine, String search, String replaceKey) {
     228    String text = value.word;
     229    if(oneLine) text = oneLine(text);
     230
     231    if(!text.contains(search)) return;
     232
     233    if(text.startsWith("\"") || text.startsWith("{")) {
     234      text = text.substring(1,text.length()-1);
     235    }
     236
     237    StringBuilder builder = new StringBuilder();
     238    int index;
     239    while((index = text.indexOf(search)) >= 0) {
     240      String between = text.substring(0, index);
     241      if(!between.isEmpty()) {
     242        if(builder.length() != 0) builder.append(" # ");
     243        builder.append("{").append(between).append("}");
     244      }
     245      if(builder.length() != 0) builder.append(" # ");
     246      builder.append(replaceKey);
     247      text = text.substring(index + search.length());
     248    }
     249    if(!text.isEmpty()) {
     250      if(builder.length() != 0) builder.append(" # ");
     251      builder.append("{").append(text).append("}");
     252    }
     253
     254
     255    document.replace(value.getStartPos(), value.getEndPos(), builder.toString());
     256  }
     257
     258  private HashSet<String> getEntryNames(SCEDocument document) {
     259    HashSet<String> names = new HashSet<String>();
     260    ArrayList<BibEntry> stringEntries = getEntries(document, null);
     261    for(BibEntry stringEntry : stringEntries) {
     262      names.add(stringEntry.getName());
     263    }
     264    return names;
     265  }
     266
    75267  public void perform(Object item) {
    76     if (item instanceof FileCreationAction) {
    77       FileCreationAction action = (FileCreationAction) item;
    78 
    79       try {
    80         File file = action.getFile();
    81         file.getParentFile().mkdirs();
    82         if (file.createNewFile()) {
    83           if (SCEManager.getInstance().isProjectUnderVersionControl()) {
    84             int res = JOptionPane.showConfirmDialog(SCEManager.getMainWindow(), "Do you want to add this file to svn?", "Question", JOptionPane.YES_NO_OPTION);
    85             if (res == JOptionPane.YES_OPTION) {
    86               SVN.getInstance().add(file);
    87             }
    88           }
    89           SCEManager.getInstance().open(new Doc.FileDoc(file));
    90         }
    91       } catch (IOException e) {
    92         e.printStackTrace();
    93       }
    94     }
    95   }
    96 
     268    final String forbiddenCharacters = "[ \\{\\}]";
     269
     270    if(item instanceof CreateStringAction) {
     271      CreateStringAction action = (CreateStringAction) item;
     272      SCEPane pane = action.getPane();
     273      SCEDocument document = pane.getDocument();
     274
     275      final HashSet<String> names = getEntryNames(document);
     276      final JTextField textField = new JTextField(action.getKey());
     277      textField.getDocument().addDocumentListener(new DocumentListener() {
     278        public void insertUpdate(DocumentEvent e) {
     279          changedUpdate(e);
     280        }
     281
     282        public void removeUpdate(DocumentEvent e) {
     283          changedUpdate(e);
     284        }
     285
     286        public void changedUpdate(DocumentEvent e) {
     287          String string = textField.getText();
     288          string = string.replaceAll(forbiddenCharacters,"");
     289
     290          if(names.contains(string) || string.isEmpty()) {
     291            textField.setBackground(new Color(255, 204, 204));
     292          } else {
     293            textField.setBackground(Color.WHITE);
     294          }
     295        }
     296      });
     297      textField.setColumns(60);
     298
     299      int ok = JOptionPane.showConfirmDialog(JLatexEditorJFrame.getFrames()[0], textField, "Enter Entry Name", JOptionPane.OK_CANCEL_OPTION);
     300      if(ok == JOptionPane.OK_OPTION && textField.getBackground().equals(Color.WHITE)) {
     301        String key = textField.getText().replaceAll(forbiddenCharacters,"");
     302
     303        document.removeSelection();
     304        pane.repaint();
     305        pane.setFreezeCaret(true);
     306        replaceAll(document, action.getString(), key);
     307        document.insert("@string{" + key + " = {" + action.getString() + "}}\n", 0, 0);
     308        pane.setFreezeCaret(false);
     309      }
     310    }
     311
     312    if(item instanceof ReplaceByAction) {
     313      ReplaceByAction action = (ReplaceByAction) item;
     314      SCEPane pane = action.getPane();
     315      SCEDocument document = pane.getDocument();
     316
     317      document.removeSelection();
     318      pane.repaint();
     319      pane.setFreezeCaret(true);
     320      replaceAll(document, action.getString(), action.getReplaceKey());
     321      pane.setFreezeCaret(false);
     322    }
     323  }
    97324
    98325// inner class
    99326
    100   class FileCreationAction {
    101     private String filename;
    102     private File file;
    103 
    104     FileCreationAction(String filename, File file) {
    105       this.filename = filename;
    106       this.file = file;
    107     }
    108 
    109     public String getFilename() {
    110       return filename;
    111     }
    112 
    113     public File getFile() {
    114       return file;
    115     }
    116 
    117     @Override
    118     public String toString() {
    119       return "<create \"" + filename + "\">";
    120     }
    121   }
     327  class CreateStringAction {
     328    private String string;
     329    private String key;
     330    private SCEPane pane;
     331
     332    CreateStringAction(String string, String key, SCEPane pane) {
     333      this.string = string;
     334      this.key = key;
     335      this.pane = pane;
     336    }
     337
     338    public String getString() {
     339      return string;
     340    }
     341
     342    public String getKey() {
     343      return key;
     344    }
     345
     346    public SCEPane getPane() {
     347      return pane;
     348    }
     349
     350    @Override
     351    public String toString() {
     352      return "Create Entry";
     353    }
     354  }
     355
     356  class ReplaceByAction {
     357    private String string;
     358    private String replaceKey;
     359    private String replaceValue;
     360    private SCEPane pane;
     361
     362    ReplaceByAction(String string, String replaceKey, String replaceValue, SCEPane pane) {
     363      this.string = string;
     364      this.replaceKey = replaceKey;
     365      this.replaceValue = replaceValue;
     366      this.pane = pane;
     367    }
     368
     369    public String getString() {
     370      return string;
     371    }
     372
     373    public String getReplaceKey() {
     374      return replaceKey;
     375    }
     376
     377    public String getReplaceValue() {
     378      return replaceValue;
     379    }
     380
     381    public SCEPane getPane() {
     382      return pane;
     383    }
     384
     385    @Override
     386    public String toString() {
     387      return "Replace by: " + replaceValue;
     388    }
     389  }
     390
     391  class WeightedElement<E> implements Comparable<WeightedElement<E>> {
     392    private double weight;
     393    private E element;
     394
     395    WeightedElement(double weight, E element) {
     396      this.weight = weight;
     397      this.element = element;
     398    }
     399
     400    public double getWeight() {
     401      return weight;
     402    }
     403
     404    public void setWeight(double weight) {
     405      this.weight = weight;
     406    }
     407
     408    public E getElement() {
     409      return element;
     410    }
     411
     412    public void setElement(E element) {
     413      this.element = element;
     414    }
     415
     416    public String toString() {
     417      return element.toString();
     418    }
     419
     420    @Override
     421    public int compareTo(WeightedElement<E> o) {
     422      return new Double(weight).compareTo(o.weight);
     423    }
     424  }
    122425}
  • trunk/src/jlatexeditor/bib/BibCodeCompletion.java

    r1414 r1444  
    1010import java.util.ArrayList;
    1111import java.util.Arrays;
     12import java.util.HashMap;
    1213
    1314public class BibCodeCompletion extends PatternCompletion {
     
    3233    int column = pane.getCaret().getColumn();
    3334
    34     ParserStateStack stateStack = BibSyntaxHighlighting.parseRow(rows[row], column);
     35    ParserStateStack stateStack = BibSyntaxHighlighting.parseRow(rows[row], column, document);
    3536    BibParserState state = (BibParserState) stateStack.peek();
    3637
     
    5051      }
    5152
    52       ArrayList<String> keys = state.getAllKeys();
    53       BibEntry entry = BibEntry.getEntry("@" + state.getEntryType());
     53      HashMap<String,BibKeyValuePair> keys = state.getEntry().getAllParameters();
     54      BibEntryPattern entry = BibEntryPattern.getEntry("@" + state.getEntry().getType());
    5455      if(entry == null) return false;
    5556
     
    5859      bibKeys.addAll(Arrays.asList(entry.getOptional()));
    5960      for(String bibKey : bibKeys) {
    60         if(!keys.contains(bibKey)) {
     61        if(!keys.containsKey(bibKey)) {
    6162          CHCommand command = new CHCommand(bibKey);
    6263          command.setUsage(bibKey + " = {@|@},");
     
    9091    if(missingParams == null) {
    9192      // entry completion
    92       for(BibEntry entry : BibEntry.ENTRIES) {
     93      for(BibEntryPattern entry : BibEntryPattern.ENTRIES) {
    9394        if(entry.getName().startsWith(name.toLowerCase())) list.add(entry);
    9495      }
  • trunk/src/jlatexeditor/bib/BibEntryPattern.java

    r1438 r1444  
    88import java.util.List;
    99
    10 public class BibEntry extends CHCommand {
     10public class BibEntryPattern extends CHCommand {
    1111  private String[] required;
    1212  private String[] optional;
    1313  private HashSet<String> all;
    1414
    15   public BibEntry(String name, String description, String[] required, String[] optional) {
     15  public BibEntryPattern(String name, String description, String[] required, String[] optional) {
    1616    super("@" + name);
    1717
     
    4747  }
    4848
    49   public static BibEntry getEntry(String type) {
     49  public static BibEntryPattern getEntry(String type) {
    5050    type = type.toLowerCase();
    51     for(BibEntry entry : ENTRIES) {
     51    for(BibEntryPattern entry : ENTRIES) {
    5252      if(entry.getName().equals(type)) return entry;
    5353    }
     
    5555  }
    5656 
    57   public static BibEntry ENTRIES[] = new BibEntry[] {
    58           new BibEntry(
     57  public static BibEntryPattern ENTRIES[] = new BibEntryPattern[] {
     58          new BibEntryPattern(
    5959                  "article",
    6060                  "An article from a journal or magazine.",
     
    6262                  new String[] {"volume", "number", "pages", "month", "note", "key"}
    6363          ),
    64           new BibEntry(
     64          new BibEntryPattern(
    6565                  "book",
    6666                  "A book with an explicit publisher.",
     
    6868                  new String[] {"volume", "series", "address", "edition", "month", "note", "key"}
    6969          ),
    70           new BibEntry(
     70          new BibEntryPattern(
    7171                  "booklet",
    7272                  "A work that is printed and bound, but without a named publisher or sponsoring institution.",
     
    7474                  new String[] {"author", "howpublished", "address", "month", "year", "note", "key"}
    7575          ),
    76           new BibEntry(
     76          new BibEntryPattern(
    7777                  "conference",
    7878                  "The same as inproceedings, included for Scribe compatibility.",
     
    8080                  new String[] {"editor", "pages", "organization", "publisher", "address", "month", "note", "key"}
    8181          ),
    82           new BibEntry(
     82          new BibEntryPattern(
    8383                  "inbook",
    8484                  "A part of a book, usually untitled. May be a chapter (or section or whatever) and/or a range of pages.",
     
    8686                  new String[] {"volume", "series", "address", "edition", "month", "note", "key"}
    8787          ),
    88           new BibEntry(
     88          new BibEntryPattern(
    8989                  "incollection",
    9090                  "A part of a book having its own title.",
     
    9292                  new String[] {"editor", "pages", "organization", "publisher", "address", "month", "note", "key"}
    9393          ),
    94           new BibEntry(
     94          new BibEntryPattern(
    9595                  "inproceedings",
    9696                  "An article in a conference proceedings.",
     
    9898                  new String[] {"editor", "series", "pages", "organization", "publisher", "address", "month", "note", "key"}
    9999          ),
    100           new BibEntry(
     100          new BibEntryPattern(
    101101                  "manual",
    102102                  "Technical documentation.",
     
    104104                  new String[] {"author", "organization", "address", "edition", "month", "year", "note", "key"}
    105105          ),
    106           new BibEntry(
     106          new BibEntryPattern(
    107107                  "mastersthesis",
    108108                  "A Master's thesis.",
     
    110110                  new String[] {"address", "month", "note", "key"}
    111111          ),
    112           new BibEntry(
     112          new BibEntryPattern(
    113113                  "misc",
    114114                  "For use when nothing else fits.",
     
    116116                  new String[] {"author", "title", "howpublished", "month", "year", "note", "key"}
    117117          ),
    118           new BibEntry(
     118          new BibEntryPattern(
    119119                  "phdthesis",
    120120                  "A Ph.D. thesis.",
     
    122122                  new String[] {"address", "month", "note", "key"}
    123123          ),
    124           new BibEntry(
     124          new BibEntryPattern(
    125125                  "proceedings",
    126126                  "The proceedings of a conference.",
     
    128128                  new String[] {"editor", "publisher", "organization", "address", "month", "note", "key"}
    129129          ),
    130           new BibEntry(
     130          new BibEntryPattern(
    131131                  "techreport",
    132132                  "A report published by a school or other institution, usually numbered within a series.",
     
    134134                  new String[] {"type", "number", "address", "month", "note", "key"}
    135135          ),
    136           new BibEntry(
     136          new BibEntryPattern(
    137137                  "unpublished",
    138138                  "A document having an author and title, but not formally published.",
  • trunk/src/jlatexeditor/bib/BibParserState.java

    r1054 r1444  
    11package jlatexeditor.bib;
    22
     3import sce.component.SCEDocumentPosition;
    34import sce.syntaxhighlighting.ParserState;
    45
    5 import java.util.ArrayList;
     6import java.util.HashMap;
    67
    78public class BibParserState implements ParserState {
     
    1718  public static final int STATE_VALUE_QUOTED = 7;
    1819  public static final int STATE_VALUE_BRACED = 8;
    19   public static final int STATE_EXPECT_CLOSE = 9;
     20  public static final int STATE_VALUE_BASIC  = 9;
     21  public static final int STATE_EXPECT_CLOSE = 10;
    2022
    2123  private int state = STATE_NOTHING;
    2224  private int bracketLevel = 0;
    23   private String entryType = null;
    24   private ArrayList<String> keys = new ArrayList<String>();
    25   private ArrayList<String> allKeys = null;
     25
     26  // current entry
     27  private BibEntry entry = new BibEntry();
     28  private BibKeyValuePair value = new BibKeyValuePair();
     29  private SCEDocumentPosition valueOpening = new SCEDocumentPosition(0,0);
     30
     31  // list of all entries
     32  private int entryNr = 0;
     33  private HashMap<Integer,BibEntry> entryByNr = new HashMap<Integer, BibEntry>();
    2634
    2735  static {
     
    3644    BibParserState copy = new BibParserState(state);
    3745    copy.bracketLevel = bracketLevel;
    38     copy.entryType = entryType;
    39     copy.keys = new ArrayList<String>(keys);
    40     copy.allKeys = allKeys;
     46    copy.entry = entry != null ? entry.copy() : null;
     47    copy.value = value.copy();
     48    copy.valueOpening = valueOpening;
     49    copy.entryNr = entryNr;
     50    copy.entryByNr = entryByNr;
    4151    return copy;
    4252  }
     
    6272  }
    6373
    64   public String getEntryType() {
    65     return entryType;
     74  public BibEntry getEntry() {
     75    return entry;
    6676  }
    6777
    68   public void setEntryType(String entryType) {
    69     this.entryType = entryType;
     78  public void setEntry(BibEntry entry) {
     79    this.entry = entry;
     80
     81    entryByNr.put(entryNr, entry);
     82    entryNr++;
    7083  }
    7184
    72   public ArrayList<String> getKeys() {
    73     return keys;
     85  public void resetEntry() {
     86    entry = new BibEntry();
    7487  }
    7588
    76   public void setKeys(ArrayList<String> keys) {
    77     this.keys = keys;
     89  public BibKeyValuePair getValue() {
     90    return value;
    7891  }
    7992
    80   public ArrayList<String> getAllKeys() {
    81     return allKeys;
     93  public void setValue(BibKeyValuePair value) {
     94    this.value = value;
    8295  }
    8396
    84   public void setAllKeys(ArrayList<String> allKeys) {
    85     this.allKeys = allKeys;
     97  public SCEDocumentPosition getValueOpening() {
     98    return valueOpening;
     99  }
     100
     101  public void setValueOpening(SCEDocumentPosition valueOpening) {
     102    this.valueOpening = valueOpening;
     103  }
     104
     105  public int getEntryNr() {
     106    return entryNr;
     107  }
     108
     109  public HashMap<Integer, BibEntry> getEntryByNr() {
     110    return entryByNr;
    86111  }
    87112
     
    89114    if(!(obj instanceof BibParserState)) return false;
    90115    BibParserState b = (BibParserState) obj;
    91     return state == b.state && bracketLevel == b.bracketLevel && equals(entryType, b.entryType) && equals(keys, b.keys);
     116    return state == b.state && bracketLevel == b.bracketLevel
     117            && equals(entry.getType(), b.getEntry().getType())
     118            && equals(entry.getParameters(), b.getEntry().getParameters())
     119            && entryNr == b.entryNr;
    92120  }
    93121
  • trunk/src/jlatexeditor/bib/BibSyntaxHighlighting.java

    r1322 r1444  
    44import jlatexeditor.syntaxhighlighting.LatexStyles;
    55import jlatexeditor.syntaxhighlighting.LatexSyntaxHighlighting;
     6import sce.codehelper.WordWithPos;
    67import sce.component.*;
    78import sce.syntaxhighlighting.ParserStateStack;
     
    910import util.SetTrie;
    1011
    11 import java.util.ArrayList;
    1212import java.util.Arrays;
     13import java.util.HashMap;
    1314
    1415/**
     
    106107      if (!row.modified) continue;
    107108
    108       // has this row a known states state?
     109      // has this row a known state?
    109110      if (row.parserStateStack != null) {
    110111        parseRow(row_nr, rows.length, rows);
     
    127128    while (!ready && row_nr < rowsCount) {
    128129      SCEDocumentRow row = rows[row_nr];
    129       ParserStateStack stateStack = parseRow(row, row.length);
     130      ParserStateStack stateStack = parseRow(row, row.length, document);
    130131
    131132      // go to the next row
     
    143144  }
    144145
    145   public static ParserStateStack parseRow(SCEDocumentRow row, int length) {
     146  public static ParserStateStack parseRow(SCEDocumentRow row, int length, SCEDocument document) {
    146147    // this may never be
    147148    if (row.parserStateStack == null) throw new RuntimeException("Internal parser error occurred.");
     
    163164      chars[char_nr].style = stateStyles[Character.isWhitespace(c) ? LatexStyles.TEXT : LatexStyles.COMMENT];
    164165
    165       // @name
     166      // @type
    166167      if(state.getState() == BibParserState.STATE_NOTHING && c == '@') {
    167168        String entryType = LatexSyntaxHighlighting.getWord(row, char_nr + 1, false);
     
    178179
    179180        state.setState(BibParserState.STATE_EXPECT_OPEN);
    180         state.setEntryType(entryType);
    181         state.setKeys(new ArrayList<String>());
    182         state.setAllKeys(new ArrayList<String>());
     181
     182        BibEntry entry = new BibEntry();
     183        state.setEntry(entry);
     184        entry.setStartPos(new SCEDocumentPosition(sce_char));
     185        entry.setType(entryType);
     186        entry.setParameters(new HashMap<String, BibKeyValuePair>());
     187        entry.setAllParameters(new HashMap<String, BibKeyValuePair>());
    183188        continue;
    184189      }
     
    189194        if(c != '{') sce_char.style = LatexStyles.ERROR;
    190195
    191         state.setState(BibParserState.STATE_EXPECT_NAME);
     196        boolean isString = state.getEntry().getType().toLowerCase().equals("string");
     197        state.setState(!isString ? BibParserState.STATE_EXPECT_NAME : BibParserState.STATE_EXPECT_KEY);
    192198        continue;
    193199      }
     
    211217        if(state.getBracketLevel() == 1) {
    212218          // exit value
     219          SCEDocumentPosition start = state.getValueOpening();
     220          SCEDocumentPosition end = new SCEDocumentPosition(sce_char,0,1);
     221          String text = document != null ? document.getText(start, end) : "";
     222
     223          state.getValue().addValue(new WordWithPos(text, start, end));
     224
    213225          state.setState(BibParserState.STATE_EXPECT_COMMA);
    214226          state.setBracketLevel(0);
    215227        } else {
    216228          // exit block
    217           state.getAllKeys().clear();
    218           state.getAllKeys().addAll(state.getKeys());
    219           state.setKeys(new ArrayList<String>());
     229          BibEntry entry = state.getEntry();
     230
     231          BibKeyValuePair value = state.getValue();
     232          if(value != null && value.getKey() != null) {
     233            entry.getParameters().put(value.getKey().word, value);
     234          }
     235
     236          entry.setEndPos(new SCEDocumentPosition(sce_char));
     237          entry.getAllParameters().clear();
     238          entry.getAllParameters().putAll(entry.getParameters());
    220239
    221240          state.setState(BibParserState.STATE_NOTHING);
    222           state.setEntryType(null);
     241          state.resetEntry();
    223242        }
    224243
     
    228247      // entry name
    229248      if(state.getState() == BibParserState.STATE_EXPECT_NAME && !Character.isWhitespace(c)) {
    230         boolean isString = state.getEntryType().toLowerCase().equals("string");
    231         char delimiter[] = !isString ? COMMA_OR_BRACKET: EQ;
     249        char delimiter[] = COMMA_OR_BRACKET;
    232250        String entryName = LatexSyntaxHighlighting.getUntil(row, char_nr, delimiter);
     251        state.getEntry().setName(entryName);
    233252        if(c == ',' || entryName == null) {
    234253          sce_char.style = stateStyles[LatexStyles.TEXT];
     
    246265        }
    247266
     267        // check whether entry name is in use
     268        for(int entryNr = 0; entryNr < state.getEntryNr()-1; entryNr++) {
     269          BibEntry previousEntry = state.getEntryByNr().get(entryNr);
     270          if(previousEntry != null) {
     271            if(entryName.equalsIgnoreCase(previousEntry.getName())) entryStyle = stateStyles[LatexStyles.getStyle("baderror")];
     272          }
     273        }
     274
    248275        for (int i = 0; i <= entryName.length(); i++) {
    249276          chars[char_nr + i].style = entryStyle;
     
    251278        char_nr += entryName.length()-1;
    252279
    253         state.setState(!isString ? BibParserState.STATE_EXPECT_COMMA : BibParserState.STATE_EXPECT_EQ);
     280        state.setState(BibParserState.STATE_EXPECT_COMMA);
    254281        continue;
    255282      }
     
    258285      if(state.getState() == BibParserState.STATE_EXPECT_COMMA && !Character.isWhitespace(c)) {
    259286        sce_char.style = stateStyles[LatexStyles.TEXT];
    260         if(c != ',') sce_char.style = LatexStyles.ERROR;
     287
     288        if(c == '#') {
     289          state.setState(BibParserState.STATE_EXPECT_VALUE);
     290          continue;
     291        } else
     292        if(c != ',') { sce_char.style = LatexStyles.ERROR; }
     293
     294        BibKeyValuePair value = state.getValue();
     295        if(value != null && value.getKey() != null) {
     296          state.getEntry().getParameters().put(value.getKey().word, value);
     297        }
    261298
    262299        state.setState(BibParserState.STATE_EXPECT_KEY);
     
    275312        byte entryStyle = stateStyles[LatexStyles.MATH_COMMAND];
    276313
    277         BibEntry entry = BibEntry.getEntry("@" + state.getEntryType());
     314        BibEntryPattern entry = BibEntryPattern.getEntry("@" + state.getEntry().getType());
    278315        if(entry != null) {
    279316          // non-existing key
     
    283320        }
    284321
     322        boolean isString = state.getEntry().getType().toLowerCase().equals("string");
     323        if(isString) {
     324          state.getEntry().setName(key);
     325
     326          // check whether entry name is in use
     327          for(int entryNr = 0; entryNr < state.getEntryNr()-1; entryNr++) {
     328            BibEntry previousEntry = state.getEntryByNr().get(entryNr);
     329            if(previousEntry != null) {
     330              if(key.equalsIgnoreCase(previousEntry.getName())) entryStyle = stateStyles[LatexStyles.getStyle("baderror")];
     331            }
     332          }
     333        }
     334
    285335        for (int i = 0; i <= key.length(); i++) {
    286336          chars[char_nr + i].style = entryStyle;
    287337        }
     338
     339        BibKeyValuePair value = new BibKeyValuePair();
     340        value.setKey(new WordWithPos(key, new SCEDocumentPosition(sce_char)));
     341        state.getEntry().getParameters().put(key, value);
     342        state.setValue(value);
     343
     344        state.setState(BibParserState.STATE_EXPECT_EQ);
     345
    288346        char_nr += key.length()-1;
    289 
    290         state.getKeys().add(key);
    291         state.setState(BibParserState.STATE_EXPECT_EQ);
    292347        continue;
    293348      }
     
    299354
    300355        state.setState(BibParserState.STATE_EXPECT_VALUE);
     356
     357        state.getValue().setEq(new WordWithPos(c +"", new SCEDocumentPosition(sce_char)));
     358
    301359        continue;
    302360      }
     
    306364        sce_char.style = stateStyles[LatexStyles.TEXT];
    307365
     366        state.setValueOpening(new SCEDocumentPosition(sce_char));
     367
    308368        if(c == '"') {
    309369          state.setState(BibParserState.STATE_VALUE_QUOTED);
    310370          continue;
     371        } else
     372        if(c == '{') {
     373          state.setState(BibParserState.STATE_VALUE_BRACED);
    311374        } else {
    312           state.setState(BibParserState.STATE_VALUE_BRACED);
    313         }
     375          state.setState(BibParserState.STATE_VALUE_BASIC);
     376        }
     377      }
     378
     379      // basic value
     380      if(state.getState() == BibParserState.STATE_VALUE_BASIC) {
     381        sce_char.style = stateStyles[LatexStyles.TEXT];
     382
     383        if(c == ',' || c == ' ') {
     384          SCEDocumentPosition start = state.getValueOpening();
     385          SCEDocumentPosition end = new SCEDocumentPosition(sce_char);
     386          String text = document != null ? document.getText(start, end) : "";
     387          state.getValue().addValue(new WordWithPos(text, start, end));
     388
     389          if(c == ',') char_nr--;
     390          state.setState(BibParserState.STATE_EXPECT_COMMA);
     391          continue;
     392        }
     393
     394        continue;
    314395      }
    315396
     
    324405        } else
    325406        if(c == '"') {
    326           boolean isString = state.getEntryType().toLowerCase().equals("string");
     407          SCEDocumentPosition start = state.getValueOpening();
     408          SCEDocumentPosition end = new SCEDocumentPosition(sce_char,0,1);
     409          String text = document != null ? document.getText(start, end) : "";
     410          state.getValue().addValue(new WordWithPos(text, start, end));
     411
     412          boolean isString = state.getEntry().getType().toLowerCase().equals("string");
     413          if(isString) state.getEntry().setName(state.getValue().getKey().word);
    327414          state.setState(!isString ? BibParserState.STATE_EXPECT_COMMA : BibParserState.STATE_EXPECT_CLOSE);
    328415        }
     
    346433        } else
    347434        if(state.getBracketLevel() == 0 && c == ',') {
    348           boolean isString = state.getEntryType().toLowerCase().equals("string");
     435          boolean isString = state.getEntry().getType().toLowerCase().equals("string");
    349436          state.setState(!isString ? BibParserState.STATE_EXPECT_COMMA : BibParserState.STATE_EXPECT_CLOSE);
    350437          char_nr--;
  • trunk/src/jlatexeditor/codehelper/BackgroundParser.java

    r1438 r1444  
    161161  public void parse() {
    162162    synchronized (syncObject) {
    163       if (parsing) return;
     163      // reparse bib file
     164      bibModified = 0;
     165
     166      if (parsing) return;
    164167      syncObject.notify();
    165168    }
  • trunk/src/jlatexeditor/codehelper/BibEntry.java

    r744 r1444  
    44
    55/**
    6  * BibEntry.
     6 * BibEntryPattern.
    77 */
    88public class BibEntry extends CHCommand {
  • trunk/src/jlatexeditor/errorhighlighting/LatexCompiler.java

    r1356 r1444  
    6969
    7070    String baseName = file.getName();
    71     baseName = baseName.substring(0, baseName.lastIndexOf(".tex"));
     71    int texIndex = baseName.lastIndexOf(".tex");
     72    if(texIndex < 0) return;
     73    baseName = baseName.substring(0, texIndex);
    7274
    7375    // Command line shell
  • trunk/src/sce/codehelper/PatternPair.java

    r1139 r1444  
    11package sce.codehelper;
    22
     3import org.jetbrains.annotations.Nullable;
    34import sce.component.SCECaret;
     5import sce.component.SCEDocumentPosition;
    46import sce.component.SCEPane;
    57import sce.component.SCEPosition;
     
    3638
    3739  public List<WordWithPos> find(SCEPane pane) {
    38     SCECaret caret = pane.getCaret();
    39 
    40     return find(pane.getDocument().getRowsModel().getRowAsString(caret.getRow()), caret.getRow(), caret.getColumn());
     40    return find(pane, null, null);
    4141  }
    4242
    4343  public List<WordWithPos> find(SCEPane pane, SCEPosition pos) {
    44     return find(pane.getDocument().getRowsModel().getRowAsString(pos.getRow()), pos.getRow(), pos.getColumn());
     44    return find(pane, pos.getRow(), pos.getColumn(), null, null);
    4545  }
    4646
    47   /**
    48    * Applies the pattern pair to the given position in the given row and
    49    * returns the list of groups as WordWithPos if the pattern could be applied or null if it could not match.
    50    *
    51    * @param rowString row string
    52    * @param row row number
    53    * @param column column number of the cursor position
    54    * @return list of groups as WordWithPos if the pattern could be applied or null if it could not match
    55    */
     47  public List<WordWithPos> find(SCEPane pane, @Nullable SCEPosition start, @Nullable SCEPosition end) {
     48    SCECaret caret = pane.getCaret();
     49
     50    return find(pane, caret.getRow(), caret.getColumn(), start, end);
     51  }
     52
     53  public List<WordWithPos> find(SCEPane pane, int row, int column, @Nullable SCEPosition start, @Nullable SCEPosition end) {
     54    String string = pane.getDocument().getRowsModel().getRowAsString(row);
     55
     56    if(end != null && row == end.getRow()) {
     57      string = string.substring(0,end.getColumn());
     58    }
     59    int shift = 0;
     60    if(start != null && row == start.getRow()) {
     61      string = string.substring(start.getColumn());
     62      shift = start.getColumn();
     63      column -= shift;
     64    }
     65
     66    return find(string, row, column, shift);
     67  }
     68
    5669  public List<WordWithPos> find(String rowString, int row, int column) {
     70    return find(rowString, row, column, 0);
     71  }
     72
     73  /**
     74   * Applies the pattern pair to the given position in the given row and
     75   * returns the list of groups as WordWithPos if the pattern could be applied or null if it could not match.
     76   *
     77   * @param rowString row string
     78   * @param row row number
     79   * @param column column number of the cursor position
     80   * @return list of groups as WordWithPos if the pattern could be applied or null if it could not match
     81   */
     82  public List<WordWithPos> find(String rowString, int row, int column, int columnShift) {
    5783    if (rowString.length() < column) return null;
    5884
     
    6894      int rightGroupMin = combine ? 2 : 1;
    6995      for (int i = 1; i <= leftGroupMax; i++) {
    70         groups.add(new WordWithPos(leftMatcher.group(i), row, leftMatcher.start(i)));
     96        groups.add(new WordWithPos(leftMatcher.group(i), row, leftMatcher.start(i)+columnShift));
    7197      }
    7298      if (combine) {
    73         groups.add(new WordWithPos(leftMatcher.group(leftGroupCount) + rightMatcher.group(1), row, leftMatcher.start(leftGroupCount)));
     99        groups.add(new WordWithPos(leftMatcher.group(leftGroupCount) + rightMatcher.group(1), row, leftMatcher.start(leftGroupCount)+columnShift));
    74100      }
    75101      for (int i = rightGroupMin; i <= rightGroupCount; i++) {
    76         groups.add(new WordWithPos(rightMatcher.group(i) + rightMatcher.group(i), row, rightMatcher.start(i)));
     102        groups.add(new WordWithPos(rightMatcher.group(i) + rightMatcher.group(i), row, rightMatcher.start(i)+columnShift));
    77103      }
    78104
  • trunk/src/sce/codehelper/WordWithPos.java

    r1272 r1444  
    2222  }
    2323
     24  public WordWithPos(String word, SCEDocumentPosition start, SCEDocumentPosition end) {
     25    super(start, end);
     26    this.word = word;
     27  }
     28
    2429  @Override
    2530  public String toString() {
  • trunk/src/sce/component/SCEDocumentRange.java

    r1272 r1444  
    5959    return endPos.getColumn();
    6060  }
     61
     62  public boolean contains(int row, int column) {
     63    if(row < startPos.getRow() || (row == startPos.getRow() && column < startPos.getColumn())) return false;
     64    if(row > endPos.getRow() || (row == endPos.getRow() && column > endPos.getColumn())) return false;
     65    return true;
     66  }
    6167}
Note: See TracChangeset for help on using the changeset viewer.