public void ProcessTextEntered(object sender, System.Windows.Input.TextCompositionEventArgs e, ref ICSharpCode.AvalonEdit.CodeCompletion.CompletionWindow completionWindow) { if (HasThrownException) { return; // exit here if intellisense has previous thrown and exception } try { if (completionWindow != null) { // close the completion window if it has no items if (!completionWindow.CompletionList.ListBox.HasItems) { completionWindow.Close(); return; } // close the completion window if the current text is a 100% match for the current item var txt = ((TextArea)sender).Document.GetText(new TextSegment() { StartOffset = completionWindow.StartOffset, EndOffset = completionWindow.EndOffset }); var selectedItem = completionWindow.CompletionList.SelectedItem; if (string.Compare(selectedItem.Text, txt, true) == 0 || string.Compare(selectedItem.Content.ToString(), txt, true) == 0) { completionWindow.Close(); } return; } if (char.IsLetterOrDigit(e.Text[0]) || "\'[".Contains(e.Text[0])) { // exit if the completion window is already showing if (completionWindow != null) { return; } // exit if we are inside a string or comment _daxState = ParseLine(); var lineState = _daxState.LineState; if (lineState == LineState.String || _editor.IsInComment()) { return; } // don't show intellisense if we are in the measure name of a DEFINE block if (DaxLineParser.IsLineMeasureDefinition(GetCurrentLine())) { return; } // TODO add insights window for Function parameters //InsightWindow insightWindow = new InsightWindow(sender as ICSharpCode.AvalonEdit.Editing.TextArea); completionWindow = new CompletionWindow(sender as ICSharpCode.AvalonEdit.Editing.TextArea); completionWindow.CloseAutomatically = false; completionWindow.CompletionList.BorderThickness = new System.Windows.Thickness(1); if (char.IsLetterOrDigit(e.Text[0])) { // if the window was opened by a letter or digit include it in the match segment //completionWindow.StartOffset -= 1; completionWindow.StartOffset = _daxState.StartOffset; System.Diagnostics.Debug.WriteLine("Setting Completion Offset: {0}", _daxState.StartOffset); } IList <ICompletionData> data = completionWindow.CompletionList.CompletionData; switch (e.Text) { case "[": string tableName = GetPreceedingTableName(); if (string.IsNullOrWhiteSpace(tableName)) { PopulateCompletionData(data, IntellisenseMetadataTypes.Measures); } else { PopulateCompletionData(data, IntellisenseMetadataTypes.Columns, _daxState); } break; case "'": PopulateCompletionData(data, IntellisenseMetadataTypes.Tables); break; default: switch (_daxState.LineState) { case LineState.Column: PopulateCompletionData(data, IntellisenseMetadataTypes.Columns, _daxState); break; case LineState.Table: PopulateCompletionData(data, IntellisenseMetadataTypes.Tables, _daxState); break; case LineState.Measure: PopulateCompletionData(data, IntellisenseMetadataTypes.Measures); break; case LineState.Dmv: PopulateCompletionData(data, IntellisenseMetadataTypes.DMV); break; default: PopulateCompletionData(data, IntellisenseMetadataTypes.ALL); break; } break; } if (data.Count > 0) { //var line = GetCurrentLine(); //System.Diagnostics.Debug.Assert(line.Length >= _daxState.EndOffset); var txt = _editor.DocumentGetText(new TextSegment() { StartOffset = _daxState.StartOffset, EndOffset = _daxState.EndOffset }); //var txt = line.Substring(_daxState.StartOffset,_daxState.EndOffset - _daxState.StartOffset); completionWindow.CompletionList.SelectItem(txt); // only show the completion window if we have valid items to display if (completionWindow.CompletionList.ListBox.HasItems) { Log.Verbose("InsightWindow == null : {IsNull}", _editor.InsightWindow == null); if (_editor.InsightWindow != null && _editor.InsightWindow.IsVisible) { Log.Verbose("hiding insight window"); _editor.InsightWindow.Visibility = Visibility.Collapsed; //_editor.InsightWindow = null; } Log.Verbose("CW null: {CompletionWindowNull} CW.Vis: {CompletionWindowVisible} IW null: {insightWindowNull} IW.Vis: {InsightWindowVisible}", completionWindow == null, completionWindow.Visibility.ToString(), _editor.InsightWindow == null, completionWindow.Visibility.ToString()); completionWindow.Show(); completionWindow.Closing += completionWindow_Closing; completionWindow.PreviewKeyUp += completionWindow_PreviewKeyUp; completionWindow.Closed += delegate { _editor.DisposeCompletionWindow(); }; } else { Log.Debug("{class} {method} {message}", "DaxIntellisenseProvider", "ProcessTextEntered", "Closing CompletionWindow as it has no matching items"); completionWindow.Close(); _editor.DisposeCompletionWindow(); completionWindow = null; } } else { _editor.DisposeCompletionWindow(); completionWindow = null; } } if (e.Text[0] == '(') { var funcName = DaxLineParser.GetPreceedingWord(GetCurrentLine().TrimEnd('(').Trim()).ToLower(); Log.Verbose("Func: {Function}", funcName); ShowInsight(funcName); } } catch (Exception ex) { HasThrownException = true; Log.Error("{class} {method} {exception} {stacktrace}", "DaxIntellisenseProvider", "ProcessTextEntered", ex.Message, ex.StackTrace); Document.OutputError(string.Format("Intellisense Disabled for this window - {0}", ex.Message)); } }
public static DaxLineState ParseLine(string line, int offset, int startOfLineOffset ) { StringBuilder sbTableName = new StringBuilder(); //LineState daxState.LineState = LineState.Other; DaxLineState daxState = new DaxLineState(LineState.NotSet, offset, 0, 0, startOfLineOffset); for (var i = 0; i < line.Length; i++) { switch (line[i]) { case '\"': if (daxState.LineState == LineState.String) daxState.SetState(LineState.Other,i); else daxState.SetState(LineState.String, i); break; case '[': if (daxState.LineState != LineState.String) { if (daxState.LineState == LineState.LetterOrDigit || daxState.LineState == LineState.TableDelimiter) { daxState.SetState(LineState.Column, i); if (i > 1 && line[i-1] != '\'') { sbTableName.Clear(); sbTableName.Append(GetPreceedingTableName(line.Substring(0, i))); } } else daxState.SetState(LineState.Measure, i); } break; case ']': if (daxState.LineState != LineState.String) daxState.SetState(LineState.Other,i); break; case '\'': if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table) { daxState.SetState(LineState.Table,i+1); sbTableName.Clear(); break; } if (daxState.LineState == LineState.Table) daxState.SetState( LineState.TableDelimiter,i); break; case '(': case '=': case '-': case '\\': case '*': case '>': case '<': case '^': case '%': case '&': case '|': case ',': case ';': case ' ': if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table && daxState.LineState != LineState.TableDelimiter && daxState.LineState != LineState.Column ) //if (daxState.LineState == LineState.Dmv) { daxState.SetState(char.IsLetterOrDigit(line[i]) ? LineState.LetterOrDigit : LineState.Other, i); } if (daxState.LineState == LineState.Table) sbTableName.Append(line[i]); break; case '.': if (GetPreceedingWord(line.Substring(0,i)).ToUpper() == "$SYSTEM") { if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table) { daxState.SetState(LineState.Dmv, i+1); } } break; default: if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table && daxState.LineState != LineState.TableDelimiter && daxState.LineState != LineState.Column && daxState.LineState != LineState.Dmv) { daxState.SetState( char.IsLetterOrDigit(line[i])?LineState.LetterOrDigit:LineState.Other ,i); } if (daxState.LineState == LineState.Table) sbTableName.Append(line[i]); break; } } daxState.TableName = sbTableName.ToString(); return daxState; }
private void PopulateCompletionData(IList <ICompletionData> data, IntellisenseMetadataTypes metadataType, DaxLineState state) { // exit early if the Metadata is not cached if (!MetadataIsCached) { return; } var tmpData = new List <ICompletionData>(); Log.Debug("{class} {method} Type: {metadataType} Table: {table} Column: {column}", "DaxIntellisenseProvider", "PopulateCompletionData", metadataType.ToString(), state == null ? "-" : state.TableName, state == null ? "-": state.ColumnName); if (metadataType.HasFlag(IntellisenseMetadataTypes.Tables) || metadataType.HasFlag(IntellisenseMetadataTypes.Columns) || metadataType.HasFlag(IntellisenseMetadataTypes.Measures)) { //var tabs = Document.Connection.Database.Models[Document.MetadataPane.SelectedModelName].Tables; var tabs = Model.Tables; foreach (var tab in tabs) { // add tables if (metadataType.HasFlag(IntellisenseMetadataTypes.Tables)) { tmpData.Add(new DaxCompletionData(this, tab, _daxState)); } // add columns or measures if ((metadataType.HasFlag(IntellisenseMetadataTypes.Columns) && (string.IsNullOrWhiteSpace(_daxState.TableName)) || (tab.Name.Equals(_daxState.TableName, StringComparison.CurrentCultureIgnoreCase))) || metadataType.HasFlag(IntellisenseMetadataTypes.Measures)) { foreach (var col in tab.Columns) { if ((col.ColumnType == ADOTabularColumnType.Column && metadataType.HasFlag(IntellisenseMetadataTypes.Columns)) || col.ColumnType == ADOTabularColumnType.Measure && metadataType.HasFlag(IntellisenseMetadataTypes.Measures)) { tmpData.Add(new DaxCompletionData(this, col, _daxState)); } } } } } // add functions if (metadataType.HasFlag(IntellisenseMetadataTypes.Functions)) { foreach (var funcGrp in Document.Connection.FunctionGroups) { foreach (var func in funcGrp.Functions) { tmpData.Add(new DaxCompletionData(this, func)); } } } if (metadataType.HasFlag(IntellisenseMetadataTypes.DMV)) { foreach (var dmv in Document.Connection.DynamicManagementViews) { tmpData.Add(new DaxCompletionData(this, dmv)); } } // add keywords if (metadataType.HasFlag(IntellisenseMetadataTypes.Keywords)) { tmpData.Add(new DaxCompletionData(this, "EVALUATE", 200.0)); tmpData.Add(new DaxCompletionData(this, "MEASURE", 200.0)); tmpData.Add(new DaxCompletionData(this, "DEFINE", 200.0)); tmpData.Add(new DaxCompletionData(this, "ORDER BY", 200.0)); tmpData.Add(new DaxCompletionData(this, "ASC", 200.0)); tmpData.Add(new DaxCompletionData(this, "DESC", 200.0)); tmpData.Add(new DaxCompletionData(this, "SELECT", 200.0)); tmpData.Add(new DaxCompletionData(this, "FROM", 200.0)); tmpData.Add(new DaxCompletionData(this, "WHERE", 200.0)); tmpData.Add(new DaxCompletionData(this, "$SYSTEM", 200.0)); } foreach (var itm in tmpData.OrderBy(x => x.Content.ToString())) { data.Add(itm); } }
public static LinePosition GetPreceedingWordSegment(int startOfLineOffset, int column, string line, DaxLineState daxState) { LinePosition segment = new LinePosition(); if (daxState != null) { switch (daxState.LineState) { case LineState.TableClosed: case LineState.ColumnClosed: case LineState.MeasureClosed: // for these states we want to replace the entire current "word" segment = new LinePosition() { Offset = startOfLineOffset + daxState.StartOffset, Length = daxState.EndOffset - daxState.StartOffset }; break; default: // for other types we want to just replace unto the current cursor position (which is the incoming "column" parameter) segment = new LinePosition() { Offset = startOfLineOffset + daxState.StartOffset, Length = column - daxState.StartOffset }; break; } } Log.Debug("{class} {method} {state} {endOffset} offset: {offset} length: {length}", "DaxLineParser", "GetPreceedingWordSegment", daxState.LineState.ToString(), column, segment.Offset, segment.Length); return(segment); }
public static DaxLineState ParseLine(string line, int offset, int startOfLineOffset) { //System.Diagnostics.Debug.WriteLine(">>> ParseLine"); // todo - can we get away with 1 string builder instance? StringBuilder sbTableName = new StringBuilder(); StringBuilder sbColumnName = new StringBuilder(); StringBuilder sbMeasureName = new StringBuilder(); //LineState daxState.LineState = LineState.Other; DaxLineState daxState = new DaxLineState(LineState.NotSet, offset, 0, 0, startOfLineOffset); if (offset == 0) { return(daxState); } for (var i = 0; i < line.Length; i++) { switch (line[i]) { case '\"': if (daxState.LineState == LineState.String) { daxState.SetState(LineState.Other, i); } else { daxState.SetState(LineState.String, i); } break; case '[': if (daxState.LineState != LineState.String) { if (daxState.LineState == LineState.LetterOrDigit || daxState.LineState == LineState.Table || daxState.LineState == LineState.TableClosed) { daxState.SetState(LineState.Column, i); sbColumnName.Clear(); if (i > 1 && line[i - 1] != '\'') { sbTableName.Clear(); sbTableName.Append(GetPreceedingTableName(line.Substring(0, i))); } } else { daxState.SetState(LineState.Measure, i); } } break; case ']': switch (daxState.LineState) { case LineState.Column: daxState.SetState(LineState.ColumnClosed, i); break; case LineState.Measure: daxState.SetState(LineState.MeasureClosed, i); break; case LineState.String: // do nothing, stay in string state break; default: daxState.SetState(LineState.Other, i); break; } break; case '\'': if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table) { //daxState.SetState(LineState.Table,i+1); daxState.SetState(LineState.Table, i); sbTableName.Clear(); break; } if (daxState.LineState == LineState.Table) { daxState.SetState(LineState.TableClosed, i); } break; case '(': case '=': case '-': case '\\': case '*': case '>': case '<': case '^': case '%': case '&': case '|': case ',': case ';': case ' ': case '\t': if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table && daxState.LineState != LineState.Column && daxState.LineState != LineState.Measure ) { daxState.SetState(line[i].IsDaxLetterOrDigit() ? LineState.LetterOrDigit : LineState.Other, i); } if (daxState.LineState == LineState.Table) { sbTableName.Append(line[i]); } if (daxState.LineState == LineState.Column) { sbColumnName.Append(line[i]); } if (daxState.LineState == LineState.Measure) { sbMeasureName.Append(line[i]); } break; case '.': if (GetPreceedingWord(line.Substring(0, i)).ToUpper() == "$SYSTEM") { if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table) { daxState.SetState(LineState.Dmv, i + 1); } } // TODO can tables have . in them?? break; default: if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table //&& daxState.LineState != LineState.TableDelimiter && daxState.LineState != LineState.Column && daxState.LineState != LineState.Dmv && daxState.LineState != LineState.Measure) { daxState.SetState(line[i].IsDaxLetterOrDigit() || line[i] == '$'?LineState.LetterOrDigit:LineState.Other, i); } if (daxState.LineState == LineState.Table) { sbTableName.Append(line[i]); } if (daxState.LineState == LineState.Column) { sbColumnName.Append(line[i]); } if (daxState.LineState == LineState.Measure) { sbMeasureName.Append(line[i]); } break; } } if (daxState.LineState != LineState.String && daxState.LineState != LineState.Table && daxState.LineState != LineState.Column && daxState.LineState != LineState.Measure ) { daxState.SetState(LineState.Other, line.Length); } daxState.TableName = sbTableName.ToString(); daxState.ColumnName = sbColumnName.ToString(); return(daxState); }
public DaxCompletionData(IInsightProvider insightProvider, ADOTabular.ADOTabularTable table, DaxLineState state) { _text = table.DaxName; _content = table.Caption; _description = string.IsNullOrEmpty(table.Description)?null:table.Description; _image = GetMetadataImage(table.MetadataImage); _priority = 100.0; _insightProvider = insightProvider; }
public DaxCompletionData(IInsightProvider insightProvider, ADOTabular.ADOTabularColumn column, DaxLineState state) { _text = string.Format("[{0}]", column.Caption); //column.DaxName; _content = column.Caption; _description = string.IsNullOrEmpty(column.Description)?null:column.Description; _image = GetMetadataImage(column.MetadataImage); _priority = 50.0; _insightProvider = insightProvider; //_lineState = state; }
public void ProcessTextEntered(object sender, System.Windows.Input.TextCompositionEventArgs e, ref ICSharpCode.AvalonEdit.CodeCompletion.CompletionWindow completionWindow) { if (HasThrownException) return; // exit here if intellisense has previous thrown and exception try { if (completionWindow != null) { // close the completion window if it has no items if (!completionWindow.CompletionList.ListBox.HasItems) { completionWindow.Close(); return; } // close the completion window if the current text is a 100% match for the current item var txt = ((TextArea)sender).Document.GetText(new TextSegment() { StartOffset = completionWindow.StartOffset, EndOffset = completionWindow.EndOffset }); var selectedItem = completionWindow.CompletionList.SelectedItem; if (string.Compare(selectedItem.Text, txt, true) == 0 || string.Compare(selectedItem.Content.ToString(), txt, true) == 0) completionWindow.Close(); return; } if (char.IsLetterOrDigit(e.Text[0]) || "\'[".Contains(e.Text[0])) { // exit if the completion window is already showing if (completionWindow != null) return; // exit if we are inside a string or comment _daxState = ParseLine(); var lineState = _daxState.LineState; if (lineState == LineState.String || _editor.IsInComment()) return; // don't show intellisense if we are in the measure name of a DEFINE block if (DaxLineParser.IsLineMeasureDefinition(GetCurrentLine())) return; // TODO add insights window for Function parameters //InsightWindow insightWindow = new InsightWindow(sender as ICSharpCode.AvalonEdit.Editing.TextArea); completionWindow = new CompletionWindow(sender as ICSharpCode.AvalonEdit.Editing.TextArea); completionWindow.CloseAutomatically = false; completionWindow.CompletionList.BorderThickness = new System.Windows.Thickness(1); if (char.IsLetterOrDigit(e.Text[0])) { // if the window was opened by a letter or digit include it in the match segment //completionWindow.StartOffset -= 1; completionWindow.StartOffset = _daxState.StartOffset; System.Diagnostics.Debug.WriteLine("Setting Completion Offset: {0}", _daxState.StartOffset); } IList<ICompletionData> data = completionWindow.CompletionList.CompletionData; switch (e.Text) { case "[": string tableName = GetPreceedingTableName(); if (string.IsNullOrWhiteSpace(tableName)) { PopulateCompletionData(data, IntellisenseMetadataTypes.Measures); } else { PopulateCompletionData(data, IntellisenseMetadataTypes.Columns, tableName); } break; case "'": PopulateCompletionData(data, IntellisenseMetadataTypes.Tables); break; default: switch (_daxState.LineState) { case LineState.Column: PopulateCompletionData(data, IntellisenseMetadataTypes.Columns, _daxState.TableName); break; case LineState.Table: PopulateCompletionData(data, IntellisenseMetadataTypes.Tables); break; case LineState.Measure: PopulateCompletionData(data, IntellisenseMetadataTypes.Measures); break; case LineState.Dmv: PopulateCompletionData(data, IntellisenseMetadataTypes.DMV); break; default: PopulateCompletionData(data, IntellisenseMetadataTypes.ALL); break; } break; } if (data.Count > 0) { //var line = GetCurrentLine(); //System.Diagnostics.Debug.Assert(line.Length >= _daxState.EndOffset); var txt = _editor.Document.GetText(new TextSegment() { StartOffset = _daxState.StartOffset, EndOffset = _daxState.EndOffset }); //var txt = line.Substring(_daxState.StartOffset,_daxState.EndOffset - _daxState.StartOffset); completionWindow.CompletionList.SelectItem(txt); // only show the completion window if we have valid items to display if (completionWindow.CompletionList.ListBox.HasItems) { completionWindow.Show(); completionWindow.Closing += completionWindow_Closing; completionWindow.PreviewKeyUp += completionWindow_PreviewKeyUp; completionWindow.Closed += delegate { _editor.DisposeCompletionWindow(); }; } else { _editor.DisposeCompletionWindow(); completionWindow = null; } } else { completionWindow = null; } } } catch(Exception ex) { HasThrownException = true; Log.Error("{class} {method} {exception} {stacktrace}", "DaxIntellisenseProvider", "ProcessTextEntered", ex.Message, ex.StackTrace); Document.OutputError(string.Format("Intellisense Disabled for this window - {0}", ex.Message)); } }