working on jEdit plugin

cvs
Slava Pestov 2005-02-17 02:54:36 +00:00
parent c1ca6b761e
commit e92757e93c
13 changed files with 460 additions and 127 deletions

View File

@ -3,10 +3,7 @@
- [ [ dup call ] dup call ] infer hangs
- move tuple to generic vocab
- update plugin docs
- extract word keeps indent
- word preview for remote words
- support USING:
- special completion for USE:/IN:
- vectors: ensure its ok with bignum indices
- code gc
- type inference fails with some assembler words;
@ -14,10 +11,11 @@
not cons, and need stronger branch partial eval
- print warning on null class
- optimize away dispatch
- alignment of gadgets inside their bounding boxes needs thought
- faster completion
- ppc register decls
- extract word inside M:, C:, and structure browsing for these
- fix checkbox alignment
- begin-scan, next-object, end-scan primitives
- each-object, each-slot combinators
- port leak

View File

@ -218,7 +218,7 @@ public class DefaultVocabularyLookup implements VocabularyLookup
return vocabs;
} //}}}
//{{{ getCompletions() method
//{{{ getWordCompletions() method
/**
* @param use A list of vocabularies.
* @param word A substring of the word name to complete
@ -226,19 +226,36 @@ public class DefaultVocabularyLookup implements VocabularyLookup
* returned; otherwise, only matches from beginning.
* @param completions Set to add completions to
*/
public void getCompletions(Cons use, String word, boolean anywhere,
public void getWordCompletions(Cons use, String word, boolean anywhere,
Set completions) throws Exception
{
while(use != null)
{
String vocab = (String)use.car;
getCompletions(vocab,word,anywhere,completions);
getWordCompletions(vocab,word,anywhere,completions);
use = use.next();
}
} //}}}
//{{{ getCompletions() method
public void getCompletions(String vocab, String word, boolean anywhere,
//{{{ isCompletion() method
public boolean isCompletion(String match, String against, boolean anywhere)
{
if(anywhere)
{
if(against.indexOf(match) != -1)
return true;
}
else
{
if(against.startsWith(match))
return true;
}
return false;
} //}}}
//{{{ getWordCompletions() method
public void getWordCompletions(String vocab, String word, boolean anywhere,
Set completions) throws Exception
{
Map v = (Map)vocabularies.get(vocab);
@ -254,21 +271,35 @@ public class DefaultVocabularyLookup implements VocabularyLookup
{
if(!completions.contains(w))
{
if(anywhere)
{
if(w.name.indexOf(word) != -1)
completions.add(w);
}
else
{
if(w.name.startsWith(word))
completions.add(w);
}
if(isCompletion(word,w.name,anywhere))
completions.add(w);
}
}
}
} //}}}
//{{{ getVocabCompletions() method
/**
* @param vocab A string to complete
* @param anywhere If true, matches anywhere in the vocab name are
* returned; otherwise, only matches from beginning.
*/
public String[] getVocabCompletions(String vocab, boolean anywhere)
throws Exception
{
List completions = new ArrayList();
Cons vocabs = getVocabularies();
while(vocabs != null)
{
String v = (String)vocabs.car;
if(isCompletion(vocab,v,anywhere))
completions.add(v);
vocabs = vocabs.next();
}
return (String[])completions.toArray(new String[completions.size()]);
} //}}}
//{{{ parseObject() method
public Cons parseObject(String source) throws Exception
{

View File

@ -238,11 +238,11 @@ public class ExternalFactor extends DefaultVocabularyLookup
}
} //}}}
//{{{ getCompletions() method
public synchronized void getCompletions(Cons use, String word,
//{{{ getWordCompletions() method
public synchronized void getWordCompletions(Cons use, String word,
boolean anywhere, Set completions) throws Exception
{
super.getCompletions(use,word,anywhere,completions);
super.getWordCompletions(use,word,anywhere,completions);
if(closed)
return;

View File

@ -49,9 +49,17 @@ public interface VocabularyLookup
* returned; otherwise, only matches from beginning.
* @param completions Set to add completions to
*/
public void getCompletions(Cons use, String word, boolean anywhere,
public void getWordCompletions(Cons use, String word, boolean anywhere,
Set completions) throws Exception;
/**
* @param vocab A string to complete
* @param anywhere If true, matches anywhere in the vocab name are
* returned; otherwise, only matches from beginning.
*/
public String[] getVocabCompletions(String vocab, boolean anywhere)
throws Exception;
/**
* @param vocab The vocabulary name
* @param word A substring of the word name to complete
@ -59,7 +67,7 @@ public interface VocabularyLookup
* the beginning of the name.
* @param completions Set to add completions to
*/
public void getCompletions(String vocab, String word, boolean anywhere,
public void getWordCompletions(String vocab, String word, boolean anywhere,
Set completions) throws Exception;
public Cons getVocabularies() throws Exception;

View File

@ -0,0 +1,81 @@
/* :folding=explicit:collapseFolds=1: */
/*
* $Id$
*
* Copyright (C) 2004, 2005 Slava Pestov.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package factor.jedit;
import factor.*;
import java.util.*;
import javax.swing.ListCellRenderer;
import org.gjt.sp.jedit.textarea.*;
import org.gjt.sp.jedit.*;
import sidekick.*;
public abstract class AbstractCompletion extends SideKickCompletion
{
protected View view;
protected JEditTextArea textArea;
protected FactorParsedData data;
//{{{ AbstractCompletion constructor
public AbstractCompletion(View view, Object[] items,
FactorParsedData data)
{
this.view = view;
textArea = view.getTextArea();
this.items = Arrays.asList(items);
this.data = data;
} //}}}
//{{{ getLongestPrefix() method
public String getLongestPrefix()
{
return MiscUtilities.getLongestPrefix(items,false);
} //}}}
//{{{ handleKeystroke() method
public boolean handleKeystroke(int selectedIndex, char keyChar)
{
if(keyChar == '\t' || keyChar == '\n')
{
insert(selectedIndex);
return false;
}
else if(keyChar == ' ')
{
insert(selectedIndex);
textArea.userInput(' ');
return false;
}
else
{
textArea.userInput(keyChar);
return true;
}
} //}}}
}

View File

@ -118,7 +118,7 @@ public class EditWordDialog extends WordListDialog
private void updateList()
{
FactorWord[] completions = FactorPlugin.toWordArray(
FactorPlugin.getCompletions(
FactorPlugin.getWordCompletions(
field.getText(),true));
list.setListData(completions);
if(completions.length != 0)

View File

@ -33,6 +33,7 @@ import factor.*;
import java.io.*;
import java.util.*;
import org.gjt.sp.jedit.gui.*;
import org.gjt.sp.jedit.syntax.*;
import org.gjt.sp.jedit.textarea.*;
import org.gjt.sp.jedit.*;
import org.gjt.sp.util.Log;
@ -325,19 +326,20 @@ public class FactorPlugin extends EditPlugin
return w;
} //}}}
//{{{ getCompletions() method
//{{{ getWordCompletions() method
/**
* Returns all words in all vocabularies.
* Returns all words in all vocabularies whose name starts with
* <code>word</code>.
*
* @param anywhere If true, matches anywhere in the word name are
* returned; otherwise, only matches from beginning.
*/
public static Set getCompletions(String word, boolean anywhere)
public static Set getWordCompletions(String word, boolean anywhere)
{
try
{
Set completions = new HashSet();
getExternalInstance().getCompletions(
getExternalInstance().getWordCompletions(
getExternalInstance().getVocabularies(),
word,
anywhere,
@ -350,6 +352,27 @@ public class FactorPlugin extends EditPlugin
}
} //}}}
//{{{ getVocabCompletions() method
/**
* Returns all vocabularies whose name starts with
* <code>vocab</code>.
*
* @param anywhere If true, matches anywhere in the word name are
* returned; otherwise, only matches from beginning.
*/
public static String[] getVocabCompletions(String vocab, boolean anywhere)
{
try
{
return getExternalInstance().getVocabCompletions(
vocab,anywhere);
}
catch(Exception e)
{
throw new RuntimeException(e);
}
} //}}}
//{{{ getWordStartIndex() method
public static int getWordStartOffset(String line, int caret)
{
@ -473,6 +496,109 @@ public class FactorPlugin extends EditPlugin
}
} //}}}
//{{{ findUse() method
/**
* Find an existing USING: declaration.
*/
private static int findUse(Buffer buffer)
{
for(int i = 0; i < buffer.getLineCount(); i++)
{
String text = buffer.getLineText(i);
int index = text.indexOf("USING:");
if(index != -1)
return index + "USING:".length();
}
return -1;
} //}}}
//{{{ createUse() method
/**
* No USING: declaration exists, so add a new one.
*/
private static void createUse(Buffer buffer, String vocab)
{
String decl = "USING: " + vocab + " ;";
int offset = 0;
boolean leadingNewline = false;
boolean trailingNewline = true;
for(int i = 0; i < buffer.getLineCount(); i++)
{
String text = buffer.getLineText(i).trim();
if(text.startsWith("IN:"))
{
offset = buffer.getLineEndOffset(i) - 1;
leadingNewline = true;
}
else if(text.startsWith("!"))
{
offset = buffer.getLineEndOffset(i) - 1;
leadingNewline = true;
}
else if(text.length() == 0)
{
if(i == 0)
offset = 0;
else
offset = buffer.getLineEndOffset(i - 1) - 1;
leadingNewline = true;
trailingNewline = false;
}
else
break;
}
decl = (leadingNewline ? "\n" : "") + decl
+ (trailingNewline ? "\n" : "");
buffer.insert(offset,decl);
} //}}}
//{{{ updateUse() method
private static void updateUse(Buffer buffer, String vocab, int offset)
{
String text = buffer.getText(0,buffer.getLength());
int end = text.indexOf(";",offset);
if(end == -1)
end = buffer.getLength();
String decl = text.substring(offset,end);
List declList = new ArrayList();
StringTokenizer st = new StringTokenizer(decl);
while(st.hasMoreTokens())
declList.add(st.nextToken());
declList.add(vocab);
Collections.sort(declList);
StringBuffer buf = new StringBuffer(" ");
Iterator iter = declList.iterator();
while(iter.hasNext())
{
buf.append(iter.next());
buf.append(' ');
}
/* format() strips trailing whitespace */
decl = TextUtilities.format(buf.toString(),
buffer.getIntegerProperty("maxLineLen",64),
buffer.getTabSize()) + " ";
try
{
buffer.beginCompoundEdit();
buffer.remove(offset,end - offset);
buffer.insert(offset,decl);
}
finally
{
buffer.endCompoundEdit();
}
} //}}}
//{{{ insertUse() method
public static void insertUse(View view, String vocab)
{
@ -483,44 +609,14 @@ public class FactorPlugin extends EditPlugin
}
Buffer buffer = view.getBuffer();
int lastUseOffset = 0;
boolean leadingNewline = false;
boolean seenUse = false;
int offset = findUse(buffer);
for(int i = 0; i < buffer.getLineCount(); i++)
{
String text = buffer.getLineText(i).trim();
if(text.startsWith("IN:") || text.startsWith("USE:"))
{
lastUseOffset = buffer.getLineEndOffset(i) - 1;
leadingNewline = true;
seenUse = true;
}
else if(text.startsWith("!") && !seenUse)
{
lastUseOffset = buffer.getLineEndOffset(i) - 1;
leadingNewline = true;
}
else if(text.length() == 0 && !seenUse)
{
if(i == 0)
lastUseOffset = 0;
else
lastUseOffset = buffer.getLineEndOffset(i - 1) - 1;
}
else
{
break;
}
}
if(offset == -1)
createUse(buffer,vocab);
else
updateUse(buffer,vocab,offset);
String decl = "USE: " + vocab;
if(leadingNewline)
decl = "\n" + decl;
if(lastUseOffset == 0)
decl = decl + "\n";
buffer.insert(lastUseOffset,decl);
showStatus(view,"inserted-use",decl);
showStatus(view,"inserted-use",vocab);
} //}}}
//{{{ extractWord() method
@ -569,8 +665,16 @@ public class FactorPlugin extends EditPlugin
try
{
buffer.beginCompoundEdit();
int firstLine = buffer.getLineOfOffset(start);
buffer.insert(start,newDef);
int lastLine = buffer.getLineOfOffset(start
+ newDef.length());
buffer.indentLines(firstLine,lastLine);
textArea.setSelectedText(newWord);
}
finally
@ -578,4 +682,27 @@ public class FactorPlugin extends EditPlugin
buffer.endCompoundEdit();
}
} //}}}
//{{{ getRulesetAtOffset() method
public static String getRulesetAtOffset(JEditTextArea textArea, int caret)
{
int line = textArea.getLineOfOffset(caret);
DefaultTokenHandler h = new DefaultTokenHandler();
textArea.getBuffer().markTokens(line,h);
Token tokens = h.getTokens();
int offset = caret - textArea.getLineStartOffset(line);
int len = textArea.getLineLength(line);
if(len == 0)
return null;
if(offset == len)
offset--;
Token token = TextUtilities.getTokenAtOffset(tokens,offset);
return token.rules.getName();
} //}}}
}

View File

@ -62,8 +62,8 @@ factor.completion.def={0} <b>{1}</b>
factor.completion.stack={0} ( {1})
# Dialog boxes
factor.status.inserted-use=Inserted {0}
factor.status.already-used=Already used {0}
factor.status.inserted-use=Using {0}
factor.status.already-used=Already using {0}
factor.insert-use.title=Insert USE: Declaration
factor.insert-use.caption=There are multiple words named "{0}". Select the one to use:

View File

@ -250,6 +250,12 @@ public class FactorSideKickParser extends SideKickParser
if(data == null)
return null;
String ruleset = FactorPlugin.getRulesetAtOffset(
editPane.getTextArea(),caret);
if(ruleset == null)
return null;
Buffer buffer = editPane.getBuffer();
// first, we get the word before the caret
@ -283,14 +289,40 @@ public class FactorSideKickParser extends SideKickParser
if(word.length() == 0)
return null;
FactorWord[] completions = FactorPlugin.toWordArray(
FactorPlugin.getCompletions(word,false));
if(ruleset.equals("factor::USING"))
return vocabComplete(editPane,data,word,caret);
else
return wordComplete(editPane,data,word,caret);
} //}}}
//{{{ vocabComplete() method
private SideKickCompletion vocabComplete(EditPane editPane,
FactorParsedData data, String vocab, int caret)
{
String[] completions = FactorPlugin.getVocabCompletions(
vocab,false);
if(completions.length == 0)
return null;
else
{
return new FactorCompletion(editPane.getView(),
return new FactorVocabCompletion(editPane.getView(),
completions,vocab,data);
}
} //}}}
//{{{ wordComplete() method
private SideKickCompletion wordComplete(EditPane editPane,
FactorParsedData data, String word, int caret)
{
FactorWord[] completions = FactorPlugin.toWordArray(
FactorPlugin.getWordCompletions(word,false));
if(completions.length == 0)
return null;
else
{
return new FactorWordCompletion(editPane.getView(),
completions,word,data);
}
} //}}}

View File

@ -0,0 +1,95 @@
/* :folding=explicit:collapseFolds=1: */
/*
* $Id$
*
* Copyright (C) 2004, 2005 Slava Pestov.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package factor.jedit;
import factor.*;
import java.util.*;
import javax.swing.*;
import org.gjt.sp.jedit.textarea.*;
import org.gjt.sp.jedit.*;
import sidekick.*;
public class FactorVocabCompletion extends AbstractCompletion
{
private String vocab;
//{{{ FactorVocabCompletion constructor
public FactorVocabCompletion(View view, String[] items,
String vocab, FactorParsedData data)
{
super(view,items,data);
this.vocab = vocab;
} //}}}
public String getLongestPrefix()
{
return MiscUtilities.getLongestPrefix(items,false);
}
public void insert(int index)
{
String selected = ((String)get(index));
String insert = selected.substring(vocab.length());
Buffer buffer = textArea.getBuffer();
textArea.setSelectedText(insert);
}
public int getTokenLength()
{
return vocab.length();
}
public boolean handleKeystroke(int selectedIndex, char keyChar)
{
if(keyChar == '\t' || keyChar == '\n')
{
insert(selectedIndex);
return false;
}
else if(keyChar == ' ')
{
insert(selectedIndex);
textArea.userInput(' ');
return false;
}
else
{
textArea.userInput(keyChar);
return true;
}
}
public ListCellRenderer getRenderer()
{
return new DefaultListCellRenderer();
}
}

View File

@ -3,7 +3,7 @@
/*
* $Id$
*
* Copyright (C) 2004 Slava Pestov.
* Copyright (C) 2004, 2005 Slava Pestov.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@ -36,29 +36,18 @@ import org.gjt.sp.jedit.textarea.*;
import org.gjt.sp.jedit.*;
import sidekick.*;
public class FactorCompletion extends SideKickCompletion
public class FactorWordCompletion extends AbstractCompletion
{
private View view;
private JEditTextArea textArea;
private String word;
private FactorParsedData data;
//{{{ FactorCompletion constructor
public FactorCompletion(View view, FactorWord[] items,
//{{{ FactorWordCompletion constructor
public FactorWordCompletion(View view, FactorWord[] items,
String word, FactorParsedData data)
{
this.view = view;
textArea = view.getTextArea();
this.items = Arrays.asList(items);
super(view,items,data);
this.word = word;
this.data = data;
} //}}}
public String getLongestPrefix()
{
return MiscUtilities.getLongestPrefix(items,false);
}
public void insert(int index)
{
FactorWord selected = ((FactorWord)get(index));
@ -85,26 +74,6 @@ public class FactorCompletion extends SideKickCompletion
return word.length();
}
public boolean handleKeystroke(int selectedIndex, char keyChar)
{
if(keyChar == '\t' || keyChar == '\n')
{
insert(selectedIndex);
return false;
}
else if(keyChar == ' ')
{
insert(selectedIndex);
textArea.userInput(' ');
return false;
}
else
{
textArea.userInput(keyChar);
return true;
}
}
public ListCellRenderer getRenderer()
{
return new FactorWordRenderer(data.parser,false);

View File

@ -91,26 +91,11 @@ public class WordPreview implements ActionListener, CaretListener
private FactorWord getWordAtCaret(FactorParsedData fdata)
throws IOException
{
int line = textArea.getCaretLine();
int caret = textArea.getCaretPosition();
DefaultTokenHandler h = new DefaultTokenHandler();
textArea.getBuffer().markTokens(line,h);
Token tokens = h.getTokens();
int offset = caret - textArea.getLineStartOffset(line);
int len = textArea.getLineLength(line);
if(len == 0)
String name = FactorPlugin.getRulesetAtOffset(textArea,
textArea.getCaretPosition());
if(name == null)
return null;
if(offset == len)
offset--;
Token token = TextUtilities.getTokenAtOffset(tokens,offset);
String name = token.rules.getName();
for(int i = 0; i < IGNORED_RULESETS.length; i++)
{
if(name.equals(IGNORED_RULESETS[i]))

View File

@ -1,7 +1,7 @@
! Copyright (C) 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license.
IN: gadgets
USING: generic kernel lists math namespaces sdl ;
USING: generic kernel lists math namespaces sdl sdl-ttf ;
! A label draws a text label, centered on the gadget's bounding
! box.
@ -14,5 +14,12 @@ C: label ( text -- )
M: label layout* ( label -- )
[ label-text dup shape-w swap shape-h ] keep resize-gadget ;
: label-x ( label -- x )
dup shape-w swap label-text shape-w - 2 /i ;
: label-y ( label -- y )
shape-h font get lookup-font TTF_FontHeight - 2 /i ;
M: label draw-shape ( label -- )
dup [ label-text draw-shape ] with-translation ;
dup label-x over label-y rect> over shape-pos +
[ label-text draw-shape ] with-translation ;