Script Editor: added Visual Studio-like snippet expanding (type the name of a snippet, then press the Tab key to expand it).

Script Editor: added snippets to auto-complete list (currently they aren't inserted properly though...).
Script Editor: auto-indentation now works a bit smarter.
ScintillaControl.GetLine() was retrieving incorrect line.
This commit is contained in:
MaxED 2014-05-13 14:41:51 +00:00
parent 3c6a9547fa
commit b4b0b4cc33
8 changed files with 206 additions and 56 deletions

View file

@ -671,6 +671,7 @@
<EmbeddedResource Include="Resources\Thing2D_0.png" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\ScriptSnippet.xpm" />
<None Include="Resources\ThingStatistics.png" />
<None Include="Resources\Copy.png" />
<None Include="Resources\Cut.png" />

View file

@ -3127,7 +3127,7 @@ namespace CodeImp.DoomBuilder.Controls
byte[] buffer = new byte[sz + 1];
fixed(byte* b = buffer)
FastPerform(2153, (uint)line + 1, (uint)b);
FastPerform(2153, (uint)line, (uint)b);
return System.Text.UTF8Encoding.UTF8.GetString(buffer, 0, sz);
}

View file

@ -48,15 +48,15 @@ namespace CodeImp.DoomBuilder.Controls
#region ================== Variables
// The script edit control
protected ScriptEditorControl editor;
protected readonly ScriptEditorControl editor;
//mxd
protected ComboBox navigator;
protected readonly ComboBox navigator;
// Derived classes must set this!
protected ScriptConfiguration config;
// The panel we're on
protected ScriptEditorPanel panel;
protected readonly ScriptEditorPanel panel;
#endregion

View file

@ -41,11 +41,12 @@ namespace CodeImp.DoomBuilder.Controls
private const int MAX_BACKTRACK_LENGTH = 200;
// Index for registered images
private enum ImageIndex : int
private enum ImageIndex
{
ScriptConstant = 0,
ScriptKeyword = 1,
ScriptError = 2
ScriptError = 2,
ScriptSnippet = 3, //mxd
}
#endregion
@ -154,6 +155,7 @@ namespace CodeImp.DoomBuilder.Controls
// Images
RegisterAutoCompleteImage(ImageIndex.ScriptConstant, Resources.ScriptConstant);
RegisterAutoCompleteImage(ImageIndex.ScriptKeyword, Resources.ScriptKeyword);
RegisterAutoCompleteImage(ImageIndex.ScriptSnippet, Resources.ScriptSnippet); //mxd
RegisterMarkerImage(ImageIndex.ScriptError, Resources.ScriptError);
// Events
@ -244,8 +246,7 @@ namespace CodeImp.DoomBuilder.Controls
Stream lexersdata;
StreamReader lexersreader;
Configuration lexercfg = new Configuration();
int imageindex;
// Make collections
stylelookup = new Dictionary<int, ScriptStyleType>();
SortedList<string, string> autocompletelist = new SortedList<string, string>(StringComparer.Ordinal);
@ -347,7 +348,7 @@ namespace CodeImp.DoomBuilder.Controls
}
// Create the keywords list and apply it
imageindex = (int)ImageIndex.ScriptKeyword;
string imageindex = ((int)ImageIndex.ScriptKeyword).ToString(CultureInfo.InvariantCulture);
int keywordsindex = lexercfg.ReadSetting(lexername + ".keywordsindex", -1);
if(keywordsindex > -1)
{
@ -356,7 +357,7 @@ namespace CodeImp.DoomBuilder.Controls
{
if(keywordslist.Length > 0) keywordslist.Append(" ");
keywordslist.Append(k);
autocompletelist.Add(k.ToUpperInvariant(), k + "?" + imageindex.ToString(CultureInfo.InvariantCulture));
autocompletelist.Add(k.ToUpperInvariant(), k + "?" + imageindex);
}
string words = keywordslist.ToString();
if(scriptconfig.CaseSensitive)
@ -366,7 +367,7 @@ namespace CodeImp.DoomBuilder.Controls
}
// Create the constants list and apply it
imageindex = (int)ImageIndex.ScriptConstant;
imageindex = ((int)ImageIndex.ScriptConstant).ToString(CultureInfo.InvariantCulture);
int constantsindex = lexercfg.ReadSetting(lexername + ".constantsindex", -1);
if(constantsindex > -1)
{
@ -375,7 +376,7 @@ namespace CodeImp.DoomBuilder.Controls
{
if(constantslist.Length > 0) constantslist.Append(" ");
constantslist.Append(c);
autocompletelist.Add(c.ToUpperInvariant(), c + "?" + imageindex.ToString(CultureInfo.InvariantCulture));
autocompletelist.Add(c.ToUpperInvariant(), c + "?" + imageindex);
}
string words = constantslist.ToString();
if(scriptconfig.CaseSensitive)
@ -383,6 +384,26 @@ namespace CodeImp.DoomBuilder.Controls
else
scriptedit.KeyWords(constantsindex, words.ToLowerInvariant());
}
//mxd. Create the snippets list and apply it
imageindex = ((int)ImageIndex.ScriptSnippet).ToString(CultureInfo.InvariantCulture);
int snippetindex = lexercfg.ReadSetting(lexername + ".snippetindex", -1);
if(snippetindex > -1 && scriptconfig.Snippets.Count > 0)
{
StringBuilder snippetslist = new StringBuilder("");
foreach(string c in scriptconfig.Snippets.Keys)
{
if(autocompletelist.ContainsKey(c.ToUpperInvariant())) continue;
if(snippetslist.Length > 0) snippetslist.Append(" ");
snippetslist.Append(c);
autocompletelist.Add(c.ToUpperInvariant(), c + "?" + imageindex);
}
string words = snippetslist.ToString();
if(scriptconfig.CaseSensitive)
scriptedit.KeyWords(snippetindex, words);
else
scriptedit.KeyWords(snippetindex, words.ToLowerInvariant());
}
// Sort the autocomplete list
List<string> autocompleteplainlist = new List<string>(autocompletelist.Values);
@ -640,24 +661,36 @@ namespace CodeImp.DoomBuilder.Controls
int numtabs = scriptedit.GetLineIndentation(curline);
string tabs = Environment.NewLine + new String(' ', numtabs);
string spaces = new String(' ', General.Settings.ScriptTabWidth);
for (int i = 0; i < lines.Length; i++) {
lines[i] = lines[i].Replace("\t", spaces);
}
string text = string.Join(tabs, lines);
scriptedit.InsertText(scriptedit.SelectionStart, text);
int entrypos = -1;
int entryline = -1;
string[] processedlines = new string[lines.Length];
//check if we have the $EP marker
for(int i = 0; i < lines.Length; i++) {
int pos = lines[i].IndexOf("$EP");
if(pos != -1) {
MoveToLine(curline + i);
pos += scriptedit.PositionFromLine(curline + i);
scriptedit.SelectionStart = pos + numtabs;
scriptedit.SelectionEnd = pos + numtabs + 3;
ReplaceSelection("");
break;
for (int i = 0; i < lines.Length; i++) {
processedlines[i] = lines[i].Replace("\t", spaces);
//check if we have the $EP marker
if (entrypos == -1) {
int pos = processedlines[i].IndexOf("$EP");
if (pos != -1) {
entryline = curline + i;
entrypos = pos + numtabs;
processedlines[i] = processedlines[i].Remove(pos, 3);
}
}
}
//replace the text
string text = string.Join(tabs, processedlines);
scriptedit.SelectionStart = scriptedit.WordStartPosition(scriptedit.CurrentPos, true);
scriptedit.SelectionEnd = scriptedit.WordEndPosition(scriptedit.CurrentPos, true);
scriptedit.ReplaceSel(text);
//move the cursor if we had the $EP marker
if (entrypos != -1) {
MoveToLine(entryline);
scriptedit.SelectionStart = scriptedit.PositionFromLine(entryline) + entrypos;
scriptedit.SelectionEnd = scriptedit.PositionFromLine(entryline) + entrypos;
}
}
#endregion
@ -693,65 +726,65 @@ namespace CodeImp.DoomBuilder.Controls
{
// These key combinations put odd characters in the script, so I disabled them
if((e.KeyCode == Keys.Q) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.W) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.E) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.R) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.Y) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.U) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.I) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.P) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.A) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
if((e.KeyCode == Keys.D) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.G) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.H) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.J) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.K) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.L) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.Z) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
if((e.KeyCode == Keys.X) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
if((e.KeyCode == Keys.C) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
if((e.KeyCode == Keys.V) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
if((e.KeyCode == Keys.B) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.N) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
if((e.KeyCode == Keys.M) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.W) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.E) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.R) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.Y) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.U) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.I) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.P) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.A) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
else if((e.KeyCode == Keys.D) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.G) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.H) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.J) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.K) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.L) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.Z) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
else if((e.KeyCode == Keys.X) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
else if((e.KeyCode == Keys.C) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
else if((e.KeyCode == Keys.V) && ((e.Modifiers & Keys.Control) == Keys.Control) && ((e.Modifiers & Keys.Shift) == Keys.Shift)) e.Handled = true;
else if((e.KeyCode == Keys.B) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.N) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
else if((e.KeyCode == Keys.M) && ((e.Modifiers & Keys.Control) == Keys.Control)) e.Handled = true;
// F3 for Find Next
if((e.KeyCode == Keys.F3) && (e.Modifiers == Keys.None))
else if((e.KeyCode == Keys.F3) && (e.Modifiers == Keys.None))
{
if(OnFindNext != null) OnFindNext();
e.Handled = true;
}
// F2 for Keyword Help
if((e.KeyCode == Keys.F2) && (e.Modifiers == Keys.None))
else if((e.KeyCode == Keys.F2) && (e.Modifiers == Keys.None))
{
LaunchKeywordHelp();
e.Handled = true;
}
// CTRL+F for find & replace
if((e.KeyCode == Keys.F) && ((e.Modifiers & Keys.Control) == Keys.Control))
else if((e.KeyCode == Keys.F) && ((e.Modifiers & Keys.Control) == Keys.Control))
{
if(OnOpenFindAndReplace != null) OnOpenFindAndReplace();
e.Handled = true;
}
// CTRL+S for save
if((e.KeyCode == Keys.S) && ((e.Modifiers & Keys.Control) == Keys.Control))
else if((e.KeyCode == Keys.S) && ((e.Modifiers & Keys.Control) == Keys.Control))
{
if(OnExplicitSaveTab != null) OnExplicitSaveTab();
e.Handled = true;
}
// CTRL+O for open
if((e.KeyCode == Keys.O) && ((e.Modifiers & Keys.Control) == Keys.Control))
else if((e.KeyCode == Keys.O) && ((e.Modifiers & Keys.Control) == Keys.Control))
{
if(OnOpenScriptBrowser != null) OnOpenScriptBrowser();
e.Handled = true;
}
// CTRL+Space to autocomplete
if((e.KeyCode == Keys.Space) && (e.Modifiers == Keys.Control))
else if((e.KeyCode == Keys.Space) && (e.Modifiers == Keys.Control))
{
// Hide call tip if any
scriptedit.CallTipCancel();
@ -763,6 +796,17 @@ namespace CodeImp.DoomBuilder.Controls
e.Handled = true;
}
//mxd. Tab to expand code snippet
else if(e.KeyCode == Keys.Tab)
{
string curword = GetCurrentWord().ToLowerInvariant();
if (scriptconfig.Snippets.ContainsKey(curword))
{
InsertSnippet(scriptconfig.Snippets[curword]);
e.Handled = true;
}
}
}
// Key released
@ -784,11 +828,17 @@ namespace CodeImp.DoomBuilder.Controls
{
// Apply identation of the previous line to this line
int ident = scriptedit.GetLineIndentation(curline - 1);
int tabs = ident ;// / scriptedit.Indent;
//mxd. Indent a bit more if a code block is started on the previous line
string prevline = scriptedit.GetLine(curline - 1);
int blockstartpos = prevline.LastIndexOf("{"); //TODO: should we move block start/end symbols to script configuration?..
int blockendpos = prevline.LastIndexOf("}");
if(blockstartpos > blockendpos) ident += General.Settings.ScriptTabWidth;
if(scriptedit.GetLineIndentation(curline) == 0)
{
scriptedit.SetLineIndentation(curline, ident);
scriptedit.SetSel(scriptedit.SelectionStart + tabs, scriptedit.SelectionStart + tabs);
scriptedit.SetSel(scriptedit.SelectionStart + ident, scriptedit.SelectionStart + ident);
}
}
}

View file

@ -564,6 +564,13 @@ namespace CodeImp.DoomBuilder.Properties {
}
}
internal static byte[] ScriptSnippet {
get {
object obj = ResourceManager.GetObject("ScriptSnippet", resourceCulture);
return ((byte[])(obj));
}
}
internal static System.Drawing.Bitmap Search {
get {
object obj = ResourceManager.GetObject("Search", resourceCulture);

View file

@ -427,4 +427,7 @@
<data name="PuzzlePiece" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\PuzzlePiece.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ScriptSnippet" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ScriptSnippet.xpm;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

View file

@ -36,6 +36,7 @@ lexer3 // CPP-style, case-sensitive
keywordsindex = 0;
constantsindex = 1;
snippetindex = 2;
}
@ -70,6 +71,7 @@ lexer18 // Pascal-style
keywordsindex = 0;
constantsindex = 1;
snippetindex = 2;
}
@ -88,6 +90,7 @@ lexer35 // CPP-style, case-insensitive
keywordsindex = 0;
constantsindex = 1;
snippetindex = 2;
}

View file

@ -0,0 +1,86 @@
/* XPM */
static char *PuzzlePiece___[] = {
/* columns rows colors chars-per-pixel */
"16 16 64 1",
" c #3C8C38",
". c #41903C",
"X c #469541",
"o c #4A9945",
"O c #4E9D48",
"+ c #51A04B",
"@ c #52A14C",
"# c #55A44F",
"$ c #59B54F",
"% c #5AA853",
"& c #5EAC57",
"* c #5CB752",
"= c #62AE5C",
"- c #60B955",
"; c #66B55F",
": c #63BA58",
"> c #65BB59",
", c #66BB5D",
"< c #68BC5B",
"1 c #69BD5D",
"2 c #6CBE5F",
"3 c #6DB566",
"4 c #6AB862",
"5 c #6BBD62",
"6 c #6DBF60",
"7 c #6EBC65",
"8 c #6FC064",
"9 c #72C165",
"0 c #72C169",
"q c #76C26A",
"w c #77C46D",
"e c #78C66F",
"r c #7AC072",
"t c #7AC770",
"y c #7CC376",
"u c #7BC971",
"i c #7DC973",
"p c #7ECB74",
"a c #80CE76",
"s c #81C67B",
"d c #87CB79",
"f c #82CE79",
"g c #84C87D",
"h c #83D079",
"j c #87CA80",
"k c #88CA81",
"l c #89CA83",
"z c #8ACB83",
"x c #8BCC83",
"c c #8DCD85",
"v c #91CF89",
"b c #94CF8B",
"n c #96D18D",
"m c #99D290",
"M c #9CD493",
"N c #9ED595",
"B c #A1D797",
"V c #A2D897",
"C c #A2D798",
"Z c #A3D899",
"A c #A4D899",
"S c #A7D99C",
"D c #E6F5E4",
"F c None",
/* pixels */
"FFFFFFFFFFFFFFFF",
"FFFFFfaiiFFFFFFF",
"FFFFDfSVwFFFFFFF",
"FFFFFiVnqFFFFFFF",
"FhapueBM74;=FFFF",
"FaSACBNMmnb&FFFF",
"FpZBdq9999b%FFFF",
"FtwgM9821>v3@OoF",
"FFF7m211>-8xkkXF",
"FFF4n1>>-*5kgg.F",
"F74rb>*-*$j=X..F",
"F4bv0cclk,gXFFFF",
"F;v-c3@O=gs.FFFF",
"F=cxl@FFXsy FFFF",
"F&%#@OFF.. FFFF",
"FFFFFFFFFFFFFFFF"
};