/// <summary> /// Toggle comment on the specified range, returns a value indicating what has been done /// 0: null, 1: toggle off; 2: toggle on, 3: added /// </summary> /// <param name="startPos"></param> /// <param name="endPos"></param> /// <returns></returns> private static int ToggleCommentOnRange(int startPos, int endPos) { // the line is essentially empty if ((endPos - startPos) == 0) { Sci.SetTextByRange(startPos, startPos, "/* */"); return(3); } // line is surrounded by /* */ if (Sci.GetTextOnRightOfPos(startPos, 2).Equals("/*") && Sci.GetTextOnLeftOfPos(endPos, 2).Equals("*/")) { if (Sci.GetTextByRange(startPos, endPos).Equals("/* */")) { // delete an empty comment Sci.SetTextByRange(startPos, endPos, String.Empty); } else { // delete /* */ Sci.SetTextByRange(endPos - 2, endPos, String.Empty); Sci.SetTextByRange(startPos, startPos + 2, String.Empty); } return(1); } Sci.SetTextByRange(endPos, endPos, "*/"); Sci.SetTextByRange(startPos, startPos, "/*"); return(2); }
/// <summary> /// Updates the CURRENT ITEMS LIST, /// handles the opening or the closing of the auto completion form on key input /// (externally called when a new char is entered or when a char is deleted) /// </summary> public static void UpdateAutocompletion(char c = char.MinValue, int insertPosition = -1) { if (_insertingWord) { return; } var typing = IsCharPartOfWord(c); var isVisible = IsVisible; // currently continuing to type a word in a visible auto completion, return asap if (typing && isVisible) { // the auto completion is already visible, this means the _currentWord is set // we only have to filter the current list even more ShowSuggestionList(_currentWord + c); return; } var nppCurrentPosition = Sci.CurrentPosition; var nppCurrentLine = Sci.Line.CurrentLine; var isNormalContext = Style.IsCarretInNormalContext(nppCurrentPosition); string strOnLeft = null; //---------------------- // we finished entering a word (we typed a char that is not part of a word, a space of new line or separator...) //---------------------- if (c != char.MinValue && !typing && isNormalContext) { strOnLeft = Sci.GetTextOnLeftOfPos(nppCurrentPosition, 61); var strOnLeftLength = strOnLeft.Length; // we finished entering a word, find the offset at which we can find said word int offset = 1; if (c == '\r' || c == '\n') { offset = nppCurrentPosition - insertPosition; if (offset > 40) { // case of an extremely hard tabbed line strOnLeft = Sci.GetTextOnLeftOfPos(nppCurrentPosition - offset, 61); } } bool textHasChanged = false; if (offset > 0 && strOnLeftLength > offset) { bool hasAtLeastOneLetter = false; var checkOffset = offset; while (IsCharPartOfWord(strOnLeft[strOnLeftLength - 1 - checkOffset])) { var ch = strOnLeft[strOnLeftLength - 1 - checkOffset]; if (char.IsLetter(ch)) { hasAtLeastOneLetter = true; break; } checkOffset++; } // See if the char of the "word" we finished entering is actually part of a word // (maybe not if, for instance, we just input 2 spaces consecutively) if (hasAtLeastOneLetter) { // automatically insert selected keyword of the completion list? if (InsertSelectedSuggestionOnWordEnd && isVisible) { InsertSuggestion(_form.GetCurrentCompletionItem(), -offset); textHasChanged = true; } // automatically change the case of the keyword? else if (AutoCase && (nppCurrentPosition - offset) != _positionOfLastInsertion) { var candidates = FindInCompletionData(strOnLeft.Substring(0, strOnLeftLength - offset), nppCurrentLine); // we matched the word in the list, correct the case if (candidates != null && candidates.Count > 0) { InsertSuggestion(candidates.First(), -offset); textHasChanged = true; } } } } // replace semicolon by a point if (c == ';' && Config.Instance.AutoCompleteReplaceSemicolon && Npp.CurrentFile.IsProgress) { _insertingWord = true; _positionOfLastInsertion = Sci.ModifyTextAroundCaret(-1, 0, "."); _insertingWord = false; textHasChanged = true; } // need to update the strOnLeft since we use it again in this method if (textHasChanged) { nppCurrentPosition = Sci.CurrentPosition; strOnLeft = Sci.GetTextOnLeftOfPos(nppCurrentPosition, 61); } } //---------------------- // We are here if the auto completion is hidden or if the user is not continuing to type a word, // So we have the opportunity to change the list of items in the auto completion if needed //---------------------- if (!_openedFromShortCut) { // don't automatically show the auto completion on input? if (!Config.Instance.AutoCompleteOnKeyInputShowSuggestions) { return; } // don't show in string/comments..? if (!isVisible && !isNormalContext && !Config.Instance.AutoCompleteShowInCommentsAndStrings) { return; } } else { // the caret changed line (happens when we trigger the auto comp manually on the first position of a line // and we press backspace, we return to the previous line but the form would still be visible) if (isVisible && nppCurrentLine != _openedFromShortcutLine) { Cloak(); return; } } // get current word if (strOnLeft == null) { strOnLeft = Sci.GetTextOnLeftOfPos(nppCurrentPosition, 61); } int charPos = 0; char?firstSeparator; var firstKeyword = GetWord(strOnLeft, ref charPos, out firstSeparator); if (typing) { // (form is not visible if we are here) Min length is not reached? if (!_openedFromShortCut && firstKeyword.Length < Config.Instance.AutoCompleteStartShowingListAfterXChar) { return; } } if (firstSeparator == null) { // we didn't match a known separator just before the keyword; // this means we want to display the entire list of keywords if (CurrentActiveTypes != ActiveTypes.All) { CurrentActiveTypes = ActiveTypes.All; DoInLock(() => { CurrentItems = _savedAllItems; }); } } else { // return the list of children that should be used in the auto completion, filtered by the previous keywords List <CompletionItem> outList = null; DoInLock(() => { var filterClass = new CompletionFilterClass(); filterClass.UpdateConditions(nppCurrentLine); outList = GetWordsList(_savedAllItems.Where(filterClass.FilterPredicate), strOnLeft, charPos, firstSeparator).ToList(); }); // empty list? if (outList == null || outList.Count == 0) { // if the current word is directly preceded by a :, we are entering an object field/method // for now, we then display the whole list of object keywords if (firstSeparator == ':' && Npp.CurrentFile.IsProgress) { if (CurrentActiveTypes != ActiveTypes.KeywordObject) { CurrentActiveTypes = ActiveTypes.KeywordObject; DoInLock(() => { CurrentItems = _savedAllItems; }); } ShowSuggestionList(firstKeyword); return; } // we should consider the first separator found not as a child separator, display the whole list if (CurrentActiveTypes != ActiveTypes.All) { CurrentActiveTypes = ActiveTypes.All; DoInLock(() => { CurrentItems = _savedAllItems; }); } } else { // we will display the list filtered with all the needed children CurrentActiveTypes = ActiveTypes.Filtered; DoInLock(() => { CurrentItems = outList.ToList(); CurrentItems.Sort(CompletionSortingClass <CompletionItem> .Instance); }); // we want to show the list no matter how long the filter keyword if (Config.Instance.AutoCompleteShowChildrenAfterSeparator) { ShowSuggestionList(firstKeyword); return; } } } // check if the minimum length of word is ok if (isVisible) { // close if (we didn't open from shortcut or we are not at the opening position) and the min length is not reached if ((!_openedFromShortCut || nppCurrentPosition < _shownPosition) && firstKeyword.Length < Config.Instance.AutoCompleteStartShowingListAfterXChar) { Cloak(); return; } // auto completion from shortcut at the end of a word and we press space, we need to close it! if (_openedFromShortCut && nppCurrentPosition > _shownPosition && c != char.MinValue) { Cloak(); return; } } else { // Min length is not reached? if (!_openedFromShortCut && firstKeyword.Length < Config.Instance.AutoCompleteStartShowingListAfterXChar) { return; } } ShowSuggestionList(firstKeyword); }