def preceding_trg_from_pos(self, buf, pos, curr_pos, preceding_trg_terminators=None, DEBUG=False): #DEBUG = True if DEBUG: log.debug("pos: %d", pos) log.debug("ch: %r", buf.accessor.char_at_pos(pos)) log.debug("curr_pos: %d", curr_pos) if pos != curr_pos and self._last_trg_type == "names": # The last trigger type was a 3-char trigger "names", we must try # triggering from the same point as before to get other available # trigger types defined at the same poisition or before. trg = ProgLangTriggerIntelMixin.preceding_trg_from_pos( self, buf, pos+2, curr_pos, preceding_trg_terminators, DEBUG=DEBUG) else: trg = ProgLangTriggerIntelMixin.preceding_trg_from_pos( self, buf, pos, curr_pos, preceding_trg_terminators, DEBUG=DEBUG) names_trigger = None style = None if pos > 0: accessor = buf.accessor if pos == curr_pos: # We actually care about whats left of the cursor. pos -= 1 style = accessor.style_at_pos(pos) if DEBUG: style_names = buf.style_names_from_style_num(style) log.debug(" style: %s (%s)", style, ", ".join(style_names)) if style in (1,2): ac = AccessorCache(accessor, pos) prev_pos, prev_ch, prev_style = ac.getPrecedingPosCharStyle(style) if prev_style is not None and (pos - prev_pos) > 3: # We need at least 3 character for proper completion handling. names_trigger = self.trg_from_pos(buf, prev_pos + 4, implicit=False) if DEBUG: log.debug("trg: %r", trg) log.debug("names_trigger: %r", names_trigger) log.debug("last_trg_type: %r", self._last_trg_type) if names_trigger: if not trg: trg = names_trigger # Two triggers, choose the best one. elif trg.pos == names_trigger.pos: if self._last_trg_type != "names": # The names trigger gets priority over the other trigger # types, unless the previous trigger was also a names trg. trg = names_trigger elif trg.pos < names_trigger.pos: trg = names_trigger if trg: self._last_trg_type = trg.type return trg
def _trg_from_pos(self, buf, pos, implicit=True, DEBUG=False, ac=None, styleClassifier=None): # DEBUG = True # not using 'logging' system, because want to be fast if DEBUG: print "\n----- %s _trg_from_pos(pos=%r, implicit=%r) -----"\ % (self.lang, pos, implicit) try: if pos == 0: return None if ac is None: ac = AccessorCache(buf.accessor, pos, fetchsize=50) else: ac.resetToPosition(pos) # Ensure this variable is initialized as False, it is used by UDL # for checking if the css style is inside of a html tag, example: # <p style="mycss: value;" /> # When it's found that it is such a case, this value is set True ac.is_html_style_attribute = False last_pos, last_char, last_style = ac.getPrevPosCharStyle() if DEBUG: print " _trg_from_pos:: last_pos: %s" % last_pos print " last_char: %r" % last_char print " last_style: %s" % last_style # All we want to know with sass is if we're in the white-space on # of after the start of a line. If yes, don't trigger, because # the user might want to just type more spaces. if styleClassifier.is_default(last_style): if DEBUG: print " _trg_from_pos:: Default style: %d, ch: %r" % (last_style, last_char) if last_char == '\n': # SASS: we don't want to put up a box until we start typing # something. if DEBUG: print "Found \\n at current pos, don't trigger." return None min_pos = max(0, pos - 200) while last_pos > min_pos: last_pos, last_char, last_style = ac.getPrevPosCharStyle() if styleClassifier.is_default(last_style): if last_char == '\n': return None else: break # Fallback and do SCSS/Less/CSS triggering. # TODO: Support ":color blue" colon-first notation. # TODO: After ",\n", offer tag-names if the above line starts with a tab. # Otherwise, indent the same level, and then offer tag-names. return _NestedCSSLangIntel._trg_from_pos(self, buf, pos, implicit=implicit, DEBUG=DEBUG, ac=None, styleClassifier=styleClassifier) except IndexError: pass
def trg_from_pos(self, buf, pos, implicit=True, lang=None): log.debug("trg_from_pos(pos=%r)", pos) if pos < 2: return None accessor = buf.accessor last_pos = pos - 1 last_char = accessor.char_at_pos(last_pos) if last_char == '.': # must be "complete-object-members" or None log.debug(" triggered 'complete-object-members'") return Trigger(self.lang, TRG_FORM_CPLN, "object-members", pos, implicit) elif last_char == '(': log.debug(" triggered 'calltip-call-signature'") return Trigger(self.lang, TRG_FORM_CALLTIP, "call-signature", pos, implicit) elif last_char in '\'"`' or last_char == "@": # Check if it's an import log.debug(" checking for import statement") ac = AccessorCache(accessor, pos, fetchsize=100) prev_style = accessor.style_at_pos(last_pos - 1) if prev_style == SCE_C_STRING: # It's the end of a string then, not what we are looking for. return False # Bug in Komodo 8 - peek at the previous style to ensure the cache # is primed. No needed in Komodo 9 onwards. p, ch, style = ac.peekPrevPosCharStyle() log.debug(" p1 %r, ch %r, style %r", p, ch, style) loops_left = 100 while loops_left: loops_left -= 1 p, ch, style = ac.getPrecedingPosCharStyle(style) log.debug(" p %r, ch %r, style %r", p, ch, style) if p is None: break if style == SCE_C_WORD: p, text = ac.getTextBackWithStyle(style) log.debug(" p %r, text %r", p, text) if text == "import": log.debug(" triggered 'complete-imports'") return Trigger(self.lang, TRG_FORM_CPLN, "imports", pos, implicit) break elif style not in (SCE_C_DEFAULT, SCE_C_OPERATOR, SCE_C_STRING, SCE_C_COMMENT, SCE_C_COMMENTDOC, SCE_C_COMMENTLINE): break log.debug(" triggered 'complete-any'") return Trigger(self.lang, TRG_FORM_CPLN, "any", pos, implicit)
def _async_eval_at_trg(self, buf, trg, ctlr, styleClassifier): if _xpcom_: trg = UnwrapObject(trg) ctlr = UnwrapObject(ctlr) # Handle ambiguous property-names here DEBUG = DebugStatus # DEBUG = True if DEBUG: print "Less: _async_eval_at_trg: trg: %s(%r)" % (trg, trg) if trg.id != (self.lang, TRG_FORM_CPLN, "tag-or-property-names"): CSSLangIntel._async_eval_at_trg( self, buf, trg, ctlr, styleClassifier) return if DEBUG: print "\n----- async_eval_at_trg(trg=%r) -----"\ % (trg) # Setup the AccessorCache extra = trg.extra ac = None # print "Extra: %r" % (extra) if isinstance(extra, dict): extra = extra.get("extra", None) if isinstance(extra, dict): ac = extra.get("ac", None) if ac and DEBUG: print " _async_eval_at_trg:: Trigger had existing AC" ac.dump() if ac is None: if DEBUG: print " _async_eval_at_trg:: Created new trigger!" ac = AccessorCache(buf.accessor, trg.pos, fetchsize=20) ctlr.start(buf, trg) pos = trg.pos try: cplns1 = [("property", v + ": ") for v in self.CSS_PROPERTY_NAMES] cplns2 = [("element", v) for v in self.CSS_HTML_TAG_NAMES] cplns = sorted(cplns1 + cplns2, key=_OrdPunctLastOnSecondItem) # Note: we add the colon as well - see bug 89913. ctlr.set_cplns(cplns) # print " _async_eval_at_trg:: cplns:", cplns ctlr.done("success") trg.retriggerOnCompletion = True except IndexError: # Tried to go out of range of buffer, nothing appropriate found if DEBUG: print " _async_eval_at_trg:: ** Out of range error **" ctlr.done("success")
def test_basics(self): content = "This is my test buffer\r\nSecond line\r\nThird line\r\n" styles = "1111011011011110111111 2 21111110001111 2 21111101111 2 2".replace(" ", "") ta = _TestAccessor(content, map(int, styles)) pos = len(content) - 2 ac = AccessorCache(ta, pos) #ac._debug = True for i in range(2): assert(ac.getPrevPosCharStyle() == (pos-1, "e", 1)) assert(ac.getPrecedingPosCharStyle(1) == (pos-5, " ", 0)) assert(ac.getPrecedingPosCharStyle(0) == (pos-6, "d", 1)) assert(ac.getPrecedingPosCharStyle(1) == (pos-11, "\n", 2)) assert(ac.getPrecedingPosCharStyle() == (pos-13, "e", 1)) assert(ac.getTextBackWithStyle(1) == (pos-16, "line")) assert(ac.getPrevPosCharStyle() == (pos-17, " ", 0)) assert(ac.getPrecedingPosCharStyle(0) == (pos-20, "d", 1)) if i == 0: ac.resetToPosition(pos) assert(ac.getCurrentPosCharStyle() == (pos-20, "d", 1)) #print pos #print ac.getSucceedingPosCharStyle() assert(ac.getNextPosCharStyle() == (pos-19, " ", 0)) assert(ac.getSucceedingPosCharStyle() == (pos-16, "l", 1)) assert(ac.getTextForwardWithStyle(1) == (pos-13, "line")) assert(ac.getNextPosCharStyle() == (pos-12, "\r", 2)) assert(ac.getNextPosCharStyle() == (pos-11, "\n", 2)) assert(ac.getSucceedingPosCharStyle(2) == (pos-10, "T", 1)) assert(ac.getSucceedingPosCharStyle() == (pos-5, " ", 0)) assert(ac.getSucceedingPosCharStyle() == (pos-4, "l", 1)) assert(ac.getSucceedingPosCharStyle() == (pos, "\r", 2)) assert(ac.getNextPosCharStyle() == (pos+1, "\n", 2)) # Bug: http://bugs.activestate.com/show_bug.cgi?id=64227 # Ensure text_range uses correct parameters in boundary situations ac.resetToPosition(3) assert(ac.getTextBackWithStyle(1)[1] == "This") ac.resetToPosition(len(content) - 2) assert(ac.getTextForwardWithStyle(2)[1] == "\r\n")
def _trg_from_pos(self, buf, pos, implicit=True, DEBUG=False, ac=None, styleClassifier=None): #DEBUG = True # not using 'logging' system, because want to be fast if DEBUG: print "\n----- %s _trg_from_pos(pos=%r, implicit=%r) -----"\ % (self.lang, pos, implicit) try: if pos == 0: return None if ac is None: ac = AccessorCache(buf.accessor, pos, fetchsize=50) else: ac.resetToPosition(pos) # Ensure this variable is initialized as False, it is used by UDL # for checking if the css style is inside of a html tag, example: # <p style="mycss: value;" /> # When it's found that it is such a case, this value is set True ac.is_html_style_attribute = False last_pos, last_char, last_style = ac.getPrevPosCharStyle() if DEBUG: print " _trg_from_pos:: last_pos: %s" % last_pos print " last_char: %r" % last_char print " last_style: %s" % last_style # The easy ones are triggering after any of '#.[: '. # For speed, let's get the common ' ' out of the way. The only # trigger on space is 'complete-property-values'. if styleClassifier.is_default(last_style): if DEBUG: print " _trg_from_pos:: Default style: %d, ch: %r" % (last_style, last_char) # Move backwards resolving ambiguity, default on "property-values" min_pos = max(0, pos - 200) while last_pos > min_pos: last_pos, last_char, last_style = ac.getPrevPosCharStyle() if styleClassifier.is_operator(last_style, ac) or styleClassifier.is_value(last_style, ac): if DEBUG: print " _trg_from_pos: space => property-values" return Trigger("CSS", TRG_FORM_CPLN, "property-values", pos, implicit, extra={"ac": ac}) elif styleClassifier.is_tag(last_style, ac): # Now we need to move further back to see which # region we're in. if DEBUG: print " _trg_from_pos: space => tag-names" return self._get_property_name_trigger_check_context(ac, styleClassifier, pos, implicit) elif styleClassifier.is_identifier(last_style, ac): if DEBUG: print " _trg_from_pos: space => property-names" return Trigger(self.lang, TRG_FORM_CPLN, "tag-or-property-names", pos, implicit, extra={"ac": ac}) if DEBUG: print " _trg_from_pos: couldn't resolve space, settling on property-names" return Trigger("CSS", TRG_FORM_CPLN, "property-values", pos, implicit, extra={"ac": ac}) elif styleClassifier.is_operator(last_style, ac): # anchors if DEBUG: print " _trg_from_pos:: OPERATOR style" if last_char == '#': return Trigger("CSS", TRG_FORM_CPLN, "anchors", pos, implicit, extra={"ac": ac}) elif last_char == ':': try: p, ch, style = ac.getPrevPosCharStyle(ignore_styles=styleClassifier.ignore_styles) if DEBUG: print " _trg_from_pos:: Looking at p: %d, ch: %r, style: %d" % (p, ch, style) except IndexError: style = None if DEBUG: print " _trg_from_pos:: style: %r" % (style) if style is None or \ not styleClassifier.is_identifier(style, ac): #if style is None or \ # not styleClassifier.is_css_style(style) or \ # styleClassifier.is_class(style, ac): # complete for pseudo-class-names return Trigger("CSS", TRG_FORM_CPLN, "pseudo-class-names", pos, implicit, extra={"ac": ac}) else: #if styleClassifier.is_identifier(style, ac): # calltip for property-values return Trigger("CSS", TRG_FORM_CALLTIP, "property-values", pos, implicit, extra={"ac": ac}) # class-names elif last_char == '.': return Trigger("CSS", TRG_FORM_CPLN, "class-names", pos, implicit, extra={"ac": ac}) # at-rule elif last_char == '@': #p, ch, style = ac.getPrevPosCharStyle(ignore_styles=styleClassifier.comment_styles) # XXX - Should check not beyond first rule set # - Should check not within a rule block. return Trigger("CSS", TRG_FORM_CPLN, "at-rule", pos, implicit, extra={"ac": ac}) # Not quite like CSS: don't handle </ # tag-names elif styleClassifier.is_tag(last_style, ac): # We trigger on tag names of specified length >= 1 char if DEBUG: print " _trg_from_pos:: TAG style" p, ch, style = last_pos, last_char, last_style try: while p >= 0: if DEBUG: print " _trg_from_pos:: Looking at p: %d, ch: %r, style: %d" % (p, ch, style) if not isident(ch): p += 1 break elif style != last_style: if DEBUG: print " _trg_from_pos:: Current style is not a tag: %d" % (style) return None p, ch, style = ac.getPrevPosCharStyle() except IndexError: p = 0 return self._get_property_name_trigger_check_context(ac, styleClassifier, p, implicit) elif styleClassifier.is_identifier(last_style, ac): if DEBUG: print " _trg_from_pos:: IDENTIFIER style" # property-names #print "here", accessor.text_range(0, pos) # We trigger on identifier names with any length >= 1 char pos = last_pos while pos >= 0: pos, ch, style = ac.getPrevPosCharStyle() if not isident(ch): break elif style != last_style: return None return self._get_property_name_trigger_check_context(ac, styleClassifier, pos + 1, implicit) elif styleClassifier.is_value(last_style, ac): p, ch, style = ac.getPrevPosCharStyle(ignore_styles=styleClassifier.comment_styles) if DEBUG: print " _trg_from_pos:: VALUE style" print " _trg_from_pos:: p: %s" % p print " _trg_from_pos:: ch: %r" % ch print " _trg_from_pos:: style: %s" % style ac.dump() # Implicit triggering only happens on a whitespace character # after any one of these ":,%) " characters # Note: last_char can be a value style yet also be whitespace # in straight CSS. if last_char in WHITESPACE: return Trigger("CSS", TRG_FORM_CPLN, "property-values", last_pos+1, implicit, extra={"ac": ac}) elif ch in WHITESPACE or ch in ":,%)": # Check to ensure this is not a pseudo-class! Bug: # http://bugs.activestate.com/show_bug.cgi?id=71073 if ch == ":": # Last style must be an identifier then! pp, pch, pstyle = ac.getPrevPosCharStyle( ignore_styles=styleClassifier.ignore_styles) if DEBUG: print "pp: %d, pch: %r, pstyle: %d" % (pp, pch, pstyle) if not styleClassifier.is_identifier(pstyle, ac): # This is likely a pseudo-class definition then, # no trigger here. if DEBUG: print "pseudo-class style found, no trigger." return None return Trigger("CSS", TRG_FORM_CPLN, "property-values", p+1, implicit, extra={"ac": ac}) # For explicit, we can also be inside a property already if not implicit and isident(ch): # If there is already part of a value there, we need to move # the trigger point "p" to the start of the value. while isident(ch): p, ch, style = ac.getPrevPosCharStyle() return Trigger("CSS", TRG_FORM_CPLN, "property-values", p+1, implicit, extra={"ac": ac}) return None elif DEBUG: print " _trg_from_pos:: Unexpected style: %d, ch: %r" % (last_style, last_char) # XXX "at-property-names" - Might be used later #elif last_style == SCE_CSS_DIRECTIVE: # # property-names # # We trigger on identifier names with length == 3 # #print "here", accessor.text_range(0, pos) # if pos >= 4 and accessor.char_at_pos(pos - 4) == ' ' and \ # self._is_ident_of_length(accessor, pos, length=3): # # We are good for completion # if DEBUG: # print "Got a trigger for 'at-property-names'" # return Trigger("CSS", TRG_FORM_CPLN, "at-property-names", # pos-3, implicit, extra={"ac": ac}) except IndexError: # Wen't out of range of buffer before we found anything useful pass if DEBUG: print "----- CSS trg_from_pos() -----" return None
def _async_eval_at_trg(self, buf, trg, ctlr, styleClassifier): if _xpcom_: trg = UnwrapObject(trg) ctlr = UnwrapObject(ctlr) # Handle ambiguous property-names here DEBUG = DebugStatus #DEBUG = True if DEBUG: print("Less: _async_eval_at_trg: trg: %s(%r)" % (trg, trg)) if trg.id == (self.lang, TRG_FORM_CPLN, "variable"): # Autocomplete Less variables from the current file and/or scope(s). cplns = [] if self.lang in buf.blob_from_lang: blob = buf.blob_from_lang[self.lang] linenum = buf.accessor.line_from_pos(trg.pos) scoperef = buf.scoperef_from_blob_and_line(blob, linenum) while scoperef: elem = scoperef[0] for lname in scoperef[1]: elem = elem.names[lname] for child in elem: if child.tag == "variable": cplns.append(("variable", child.get("name"))) if scoperef[1]: scoperef = (scoperef[0], scoperef[1][:-1]) else: scoperef = None ctlr.set_cplns(sorted(cplns)) ctlr.done("success") return elif trg.id != (self.lang, TRG_FORM_CPLN, "tag-or-property-names"): CSSLangIntel._async_eval_at_trg(self, buf, trg, ctlr, styleClassifier) return if DEBUG: print("\n----- async_eval_at_trg(trg=%r) -----"\ % (trg)) # Setup the AccessorCache extra = trg.extra ac = None #print "Extra: %r" % (extra) if isinstance(extra, dict): extra = extra.get("extra", None) if isinstance(extra, dict): ac = extra.get("ac", None) if ac and DEBUG: print(" _async_eval_at_trg:: Trigger had existing AC") ac.dump() if ac is None: if DEBUG: print(" _async_eval_at_trg:: Created new trigger!") ac = AccessorCache(buf.accessor, trg.pos, fetchsize=20) ctlr.start(buf, trg) pos = trg.pos try: cplns1 = [("property", v + ": ") for v in self.CSS_PROPERTY_NAMES] cplns2 = [("element", v) for v in self.CSS_HTML_TAG_NAMES] cplns = sorted(cplns1 + cplns2, key=_OrdPunctLastOnSecondItem) # Note: we add the colon as well - see bug 89913. ctlr.set_cplns(cplns) #print " _async_eval_at_trg:: cplns:", cplns ctlr.done("success") trg.retriggerOnCompletion = True except IndexError: # Tried to go out of range of buffer, nothing appropriate found if DEBUG: print(" _async_eval_at_trg:: ** Out of range error **") ctlr.done("success")