def onTimerMiddleButton(self): middleButton = windll.user32.GetKeyState(VK_MBUTTON) if self.middleButton != middleButton and (middleButton - (middleButton & 1)) != 0: x, y = GetCursorPos() hFore = windll.user32.GetForegroundWindow() hPoint = windll.user32.WindowFromPoint(x, y) if hPoint == hFore: hPoint = windll.user32.ChildWindowFromPoint(hFore, x, y) hSelf = self.windowHandle x0, y0, x1, y1 = GetWindowRect(hPoint) if x0 <= x <= x1 and y0 <= y <= y1 and hSelf == hFore: editor.grabFocus() pos = editor.positionFromPoint(x - x0, y - y0) iLineClick = editor.lineFromPosition(pos) iStart = editor.getSelectionStart() iEnd = editor.getSelectionEnd() iLineStart = editor.lineFromPosition(iStart) iLineEnd = editor.lineFromPosition(iEnd) if iStart != iEnd and iLineStart <= iLineClick <= iLineEnd: self.runCodeAtCursor(moveCursor=False, onlyInsideCodeLines=True) elif 0 <= pos < editor.getLength(): self.runCodeAtCursor(moveCursor=False, nonSelectedLine=iLineClick, onlyInsideCodeLines=True) self.middleButton = middleButton threading.Timer(self.tTimerMiddleButton, self.onTimerMiddleButton).start()
def textModified(self, args): '''When the marked text is modified the execution markers will be hidden, except when the code is still running.''' if args['text'] != '': bufferID = notepad.getCurrentBufferID() if self.markers.get( bufferID, None) is not None and not self.bufferActive and len( self.markers[bufferID]) > 0: iCurrentLine = editor.lineFromPosition(editor.getCurrentPos()) iLines = [] for i in self.markers[bufferID]: iLine = editor.markerLineFromHandle(i) iLines.append(iLine) if min(iLines) <= iCurrentLine <= max(iLines): self.hideMarkers(bufferID) if self.markers.get( bufferID, None) is not None and self.bufferActive and len( self.markers[bufferID]) > 0: iCurrentLine = editor.lineFromPosition(editor.getCurrentPos()) iLines = [] for i in self.markers[bufferID]: iLine = editor.markerLineFromHandle(i) iLines.append(iLine) if len(iLines) > 0 and min(iLines) <= iCurrentLine <= max( iLines): self.setMarkers(min(iLines), max(iLines), iMarker=self.m_active, bufferID=bufferID, startAnimation=False)
def _send_document_range_formatting(self): _start_pos = editor.getSelectionStart() start_line = editor.lineFromPosition(_start_pos) start_char_pos = _start_pos - editor.positionFromLine(start_line) _end_pos = editor.getSelectionEnd() end_line = editor.lineFromPosition(_end_pos) end_char_pos = _end_pos - editor.positionFromLine(end_line) self.com_manager.send( self.lsp_msg.rangeFormatting(self.current_file, self._get_file_version(), (start_line, start_char_pos), (end_line, end_char_pos))) self.open_results[ self.lsp_msg.request_id] = self.document_range_formatting_handler
def logfile_lexer(self, start_pos, end_pos): ''' Main lexing logic. Gets called by styleneeded callback ''' def style_it(match, STYLE): ''' Inform scintilla to do the styling''' if match[1]-match[0] >= 0: editor.startStyling(start_pos + match[0], 31) editor.setStyling(match[1]-match[0], STYLE) def do_regex(regex): ''' return a list of match positions Note, is using python regular expression instead of boost::re ''' return [m.span(0) for m in re.finditer(regex, text, flags=re.I)] # ensure that position is really the first position for each line start_pos = editor.positionFromLine(editor.lineFromPosition(start_pos)) # fast but potentially unsafe way to get the text of the line text = editor.getRangePointer(start_pos, end_pos-start_pos) # first everything will be styled with default style style_it((start_pos, end_pos), self.DEFAULT) # map style_it function to each match returned by do_regex # ordering is important as it might be that a line matches # multiple regexes - the last do_regex overwrites previous styling map(lambda match: style_it(match, self.WARNING_STYLE), do_regex(self.WARNING_REGEX)) map(lambda match: style_it(match, self.ERROR_STYLE), do_regex(self.ERROR_REGEX)) # this needs to stay and to be the last line, to signal scintilla we are done. editor.startStyling(end_pos,31)
def on_char_added(self, args): if self.lsp_doc_flag: if chr(args['ch']) == ')': editor.callTipCancel() elif (args['ch'] in self.current_triggers[ self.current_language]['signatureHelpProvider'] or args['ch'] in self.current_triggers[ self.current_language]['completionProvider']): cur_pos = editor.getCurrentPos() _line = editor.lineFromPosition(cur_pos) _character_pos = cur_pos - editor.positionFromLine(_line) _version = self._set_file_version() self._send_did_change(_version) if args['ch'] in self.current_triggers[ self.current_language]['signatureHelpProvider']: self.com_manager.send( self.lsp_msg.signatureHelp( self.current_file, self.current_language.lower(), _version, editor.getText(), _line, _character_pos)) self.open_results[ self.lsp_msg. request_id] = self.signature_response_handler else: self.com_manager.send( self.lsp_msg.completion( *self.__TextDocumentPositionParams())) self.open_results[ self.lsp_msg. request_id] = self.completion_response_handler
def getUncompleteLine(self, iPos): '''get the whole expression with the context of a variable that is required to evaluate the variable''' iLine = editor.lineFromPosition(iPos) iStart = editor.positionFromLine(iLine) linePart = editor.getTextRange(iStart, iPos - 1) return linePart
def __TextDocumentPositionParams(self, cur_pos=None): if cur_pos is None: cur_pos = editor.getCurrentPos() _line = editor.lineFromPosition(cur_pos) _character_pos = editor.getColumn(cur_pos) _file, _version = self.__TextDocumentIdentifier() return _file, _version, _line, _character_pos
def calculate_checksum(self): ''' Calculates the checksum of the caret line Args: None Returns: None ''' line = editor.getCurLine().strip() line_length = len(line) record_length = line_length - 1 if line.startswith(':') and line_length > 10 and (record_length % 2 == 0): if record_length == int(line[1:3], 16) * 2 + 8: length_assumed = True x = line[1:].decode('hex') else: length_assumed = False x = line[1:-2].decode('hex') total = sum(struct.unpack('<' + 'B' * len(x), x)) int_checksum = ~total & 0xFF checksum = format(0 if int_checksum == 0xFF else int_checksum + 1, '02X') if self.debug_mode: print('calculated checksum is {}'.format(checksum)) if checksum != line[-2:]: self.__set_annotation( editor.lineFromPosition(editor.getCurrentPos()), '{}{}'.format( ' ' * line_length if length_assumed else ' ' * (line_length - 2), checksum)) else: editor.annotationClearAll()
def async_callback_MARGINCLICK(args): # as unfold hasn't finished yet # we need asynchronous call to be # able to rehide if needed, if args['margin'] == 2: # folding margin clicked_line = editor.lineFromPosition(args['position']) if editor.getFoldExpanded(clicked_line): rehide_lines(clicked_line, editor.getLineCount())
def styleneeded_callback(self,args): ''' Called by scintilla to inform the lexer about the need to style the document. If document is of interest call main logic (column_lexer) function Ensures that the start position is really the first position per line ''' if self.is_lexer_doc(): startPos = editor.getEndStyled() lineNumber = editor.lineFromPosition(startPos) startPos = editor.positionFromLine(lineNumber) self.column_lexer(startPos, args['position'])
def styleneeded_callback(self, args): ''' Called by scintilla to inform the lexer about the need to style the document. If document is of interest call main logic (logfile_lexer) function Ensures that the start position is really the first position per line ''' if self.is_lexer_doc(): startPos = editor.getEndStyled() lineNumber = editor.lineFromPosition(startPos) startPos = editor.positionFromLine(lineNumber) self.logfile_lexer(startPos, args['position'])
def paint_it(indicator, pos, length): current_line = editor.lineFromPosition(pos) line_start_position = editor.positionFromLine(current_line) text = editor.getLine(current_line) found_comment_char = text.find('#') relative_line_position = pos-line_start_position if((-1 < found_comment_char < relative_line_position) or (text.count('"', 0, relative_line_position) % 2 == 1) or (text.count("'", 0, relative_line_position) % 2 == 1)): return else: editor.setIndicatorCurrent(indicator) editor.indicatorFillRange(pos,length)
def paint_it(indicator, pos, length): current_line = editor.lineFromPosition(pos) line_start_position = editor.positionFromLine(current_line) text = editor.getLine(current_line) found_comment_char = text.find('#') relative_line_position = pos - line_start_position if ((-1 < found_comment_char < relative_line_position) or (text.count('"', 0, relative_line_position) % 2 == 1) or (text.count("'", 0, relative_line_position) % 2 == 1)): return else: editor.setIndicatorCurrent(indicator) editor.indicatorFillRange(pos, length)
def column_lexer(self, start_pos, end_pos): ''' Main lexing logic. Gets called by styleneeded callback ''' def style_it(start, length, STYLE): ''' Inform scintilla to do the styling''' if length >= 0: editor.startStyling(start, 31) editor.setStyling(length, STYLE) # first everything will be styled with default style style_it(start_pos, end_pos-start_pos, self.DEFAULT) # loop over line indexes from start_pos and end_pos for line in range(editor.lineFromPosition(start_pos), editor.lineFromPosition(end_pos)): # get start position for each line line_start_pos = editor.positionFromLine(line) # split current line into columns columns = editor.getLine(line).split(self.COLUMN_SEPARATOR) if columns > 0: # iterate over all columns for i, column in enumerate(columns): # get the width of the current column col_length = len(column) if i % 2 == 0: # even column style_it(line_start_pos,col_length,self.EVEN_COLUMN_STYLE) else: # odd column style_it(line_start_pos,col_length, self.ODD_COLUMN_STYLE) # recalculate start position for next column line_start_pos += col_length+1 # this needs to stay and to be the last line, to signal scintilla we are done. editor.startStyling(end_pos,31)
def peek_definition_response_handler(self, decoded_message): log(decoded_message) if decoded_message['result']: _file = url2pathname(decoded_message['result'][0]['uri'].replace( 'file:', '')) _line_number = decoded_message['result'][0]['range']['start'][ 'line'] with open(_file) as f: for i, line in enumerate(f): if i == _line_number: break cursor_line = editor.lineFromPosition(editor.getCurrentPos()) editor.annotationSetText( cursor_line, '\n{}\n'.format(line[:-1] if line.endswith('\n') else line)) editor.annotationSetStyle(cursor_line, self.PEEK_STYLE) editor.annotationSetVisible(ANNOTATIONVISIBLE.STANDARD)
def sync_callback_MARGINCLICK(args): if args['margin'] == 1: # symbol margin clicked_line = editor.lineFromPosition(args['position']) current_marker_mask = editor.markerGet(clicked_line) # if clicked on a opening marker - find corresponding end marker if (current_marker_mask & MARK_HIDELINESBEGIN_MASK) == MARK_HIDELINESBEGIN_MASK: end_line = find_correspondig_marker(clicked_line, MARK_HIDELINESEND_MASK) show_lines(clicked_line, end_line) # else if clicked on a closing marker, then find corresponding start marker elif (current_marker_mask & MARK_HIDELINESEND_MASK) == MARK_HIDELINESEND_MASK: start_line = find_correspondig_marker(clicked_line, MARK_HIDELINESBEGIN_MASK) show_lines(start_line, clicked_line) else: # no hiding marker, just bookmark toggle_bookmark(clicked_line) # cheating npp ;-) toggle_bookmark(clicked_line) # double cheating npp :D
def logfile_lexer(self, start_pos, end_pos): ''' Main lexing logic. Gets called by styleneeded callback ''' def style_it(match, STYLE): ''' Inform scintilla to do the styling''' if match[1] - match[0] >= 0: editor.startStyling(start_pos + match[0], 31) editor.setStyling(match[1] - match[0], STYLE) def do_regex(regex): ''' return a list of match positions Note, is using python regular expression instead of boost::re ''' return [ m.span(0) for m in re.finditer(regex, text, flags=re.I) ] # ensure that position is really the first position for each line start_pos = editor.positionFromLine( editor.lineFromPosition(start_pos)) # fast but potentially unsafe way to get the text of the line text = editor.getRangePointer(start_pos, end_pos - start_pos) # first everything will be styled with default style style_it((start_pos, end_pos), self.DEFAULT) # map style_it function to each match returned by do_regex # ordering is important as it might be that a line matches # multiple regexes - the last do_regex overwrites previous styling map(lambda match: style_it(match, self.WARNING_STYLE), do_regex(self.WARNING_REGEX)) map(lambda match: style_it(match, self.ERROR_STYLE), do_regex(self.ERROR_REGEX)) # this needs to stay and to be the last line, to signal scintilla we are done. editor.startStyling(end_pos, 31)
def test_scintillawrapper_int_position_void_lineFromPosition(self): editor.write('Hello World\r\nCheese\r\nCheddar') lineOfCheddar = editor.lineFromPosition(24) self.assertEqual(lineOfCheddar, 2)
def paint_it(indicator, pos, length): current_line = editor.lineFromPosition(pos) editor.setIndicatorCurrent(indicator) editor.indicatorFillRange(pos, length)
def showCalltip(self, pos=None): iStart = editor.getSelectionStart() iEnd = editor.getSelectionEnd() if pos is None: pos = editor.getCurrentPos() CT_unselected = True CT_expression = True else: CT_unselected = self.popupForUnselectedVariable CT_expression = self.popupForSelectedExpression if iEnd != iStart and iStart <= pos <= iEnd: if CT_expression and iEnd - iStart > 1: expression = editor.getTextRange(iStart, iEnd) if expression == 'False': self.activeCalltip = False editor.callTipShow(iStart, 'set to True') elif expression == 'True': self.activeCalltip = True editor.callTipShow(iStart, 'set to False') elif not '\n' in expression: ret = self.interp.getCallTip(None, expression) if ret and (CT_unselected or ret[-1] != 'value error'): element, nHighlight, calltip = ret self.activeCalltip = 'doc' editor.callTipShow(iStart, ''.join(calltip)) editor.callTipSetHlt(0, int(nHighlight)) else: iLineStart = editor.positionFromLine( editor.lineFromPosition(iStart)) var = editor.getTextRange(iStart, iEnd) line = editor.getTextRange(iLineStart, iEnd) if var == '.': autoCompleteList = self.interp.autoCompleteObject( self.getUncompleteLine(iStart + 1)) if autoCompleteList: editor.autoCSetSeparator(ord('\t')) editor.autoCSetIgnoreCase(False) editor.autoCSetCaseInsensitiveBehaviour(False) editor.autoCSetOrder(0) editor.autoCSetDropRestOfWord(True) editor.autoCShow(0, autoCompleteList) else: ret = self.interp.getCallTip(line, var) if ret: element, nHighlight, calltip = ret if element == var == 'False': self.activeCalltip = False editor.callTipShow(iStart, 'set to True') elif element == var == 'True': self.activeCalltip = True editor.callTipShow(iStart, 'set to False') elif ret[-1] != 'value error': self.activeCalltip = 'doc' editor.callTipShow(iStart, ''.join(calltip)) editor.callTipSetHlt(0, int(nHighlight)) elif CT_unselected and iStart == iEnd and pos >= 0: iLine = editor.lineFromPosition(pos) line = editor.getLine(iLine) iLineStart = editor.positionFromLine(iLine) posInLine = pos - iLineStart iWordEnd = 0 for iWordStart in range(posInLine, -1, -1): s = line[iWordStart] if not ('a' <= s <= 'z' or 'A' <= s <= 'Z' or '0' <= s <= '9' or s == '_'): iWordStart += 1 break if iWordStart <= posInLine: for iWordEnd in range(posInLine + 1, len(line)): s = line[iWordEnd] if not ('a' <= s <= 'z' or 'A' <= s <= 'Z' or '0' <= s <= '9' or s == '_'): iWordEnd -= 1 break var = line[iWordStart:iWordEnd + 1] if var: var = line[iWordStart:iWordEnd + 1] ret = self.interp.getCallTip(line[0:iWordEnd + 1], var) pos = iLineStart + iWordStart if ret: element, nHighlight, calltip = ret if calltip != 'value error': self.activeCalltip = 'doc' editor.callTipShow(pos, ''.join(calltip)) editor.callTipSetHlt(0, int(nHighlight))
def runThread(self, moveCursor=True, nonSelectedLine=None, onlyInsideCodeLines=False): '''Executes the smallest possible code element for the current selection. Or execute one marked cell.''' bufferID = notepad.getCurrentBufferID() self.bufferActive = bufferID lang = notepad.getLangType() filename = notepad.getCurrentFilename() if lang == Npp.LANGTYPE.TXT and '.' not in os.path.basename(filename): notepad.setLangType(Npp.LANGTYPE.PYTHON) elif lang != Npp.LANGTYPE.PYTHON: self.bufferActive = 0 return if nonSelectedLine is None: iSelStart = editor.getSelectionStart() iSelEnd = editor.getSelectionEnd() iPos = editor.getCurrentPos() iLineCursor = iLineStart = editor.lineFromPosition(iSelStart) iLineEnd = max(iLineStart, editor.lineFromPosition(iSelEnd - 1)) else: iLineCursor = iLineStart = iLineEnd = nonSelectedLine iSelStart = iSelEnd = 0 selection = iSelStart != iSelEnd startLine = editor.getLine(iLineStart).rstrip() cellMode = not selection and (startLine.startswith('#%%') or startLine.startswith('# %%')) err = None if not cellMode: getLineEnd = self.completeBlockEnd(iLineStart, iLineMin=iLineEnd, iLineMax=editor.getLineCount() - 1) iFirstCodeLine, iLineEnd, isEmpty, inspectLineBefore = next( getLineEnd) if not inspectLineBefore and iFirstCodeLine: iLineStart = iFirstCodeLine if isEmpty: self.hideMarkers(bufferID) self.bufferActive = 0 return iLineStart = self.completeBlockStart(iLineStart, inspectLineBefore) requireMore = True iStart = editor.positionFromLine(iLineStart) iDocEnd = editor.getLength() if cellMode: iMatch = [] editor.research('^# ?%%(.*)$', lambda m: iMatch.append(m.span(0)[0] - 1), 0, iStart + 4, iDocEnd - 1, 1) iEnd = iMatch[0] if len(iMatch) else iDocEnd iLineEnd = editor.lineFromPosition(iEnd) block = editor.getTextRange(iStart, iEnd).rstrip() r = self.interp.tryCode(iLineStart, filename, block) if r is None: self.hideMarkers(bufferID) self.bufferActive = 0 return err, requireMore, isValue = r if requireMore: err = True else: # add more lines until the parser is happy or finds # a syntax error while requireMore: iEnd = editor.getLineEndPosition(iLineEnd) block = editor.getTextRange(iStart, iEnd).rstrip() if block: res = self.interp.tryCode(iLineStart, filename, block) if res is None: self.bufferActive = 0 return else: err, requireMore, isValue = res else: err, requireMore, isValue = None, True, False if requireMore: nextLine = next(getLineEnd, None) if nextLine is None: self.bufferActive = 0 iEnd = editor.getLength() block = editor.getTextRange(iStart, iEnd).rstrip() err, buff = self.interp.execute( block, iLineStart, filename) self.outBuffer(buff) self.setMarkers(iLineStart, iLineEnd, block, iMarker=self.m_error, bufferID=bufferID) return iCodeLineStart, iLineEnd, isEmpty, inspectLineBefore = nextLine if onlyInsideCodeLines and not selection and not iLineStart <= iLineCursor <= iLineEnd: self.hideMarkers() self.bufferActive = 0 return if self.activeCalltip: editor.callTipCancel() self.activeCalltip = None self.setMarkers(iLineStart, iLineEnd, block, iMarker=(self.m_active if not err else self.m_error), bufferID=bufferID) if err is not None: if moveCursor: editor.setSelectionStart(iStart) editor.scrollRange(iEnd, iStart) if err is not True: self.outBuffer(err) else: # Check if correct path is set if self.lastActiveBufferID != bufferID and '.' in os.path.basename( filename): filePath = os.path.normpath(os.path.split(filename)[0]) self.interp.execute('os.chdir(' + repr(filePath) + ')') self.lastActiveBufferID = bufferID # Start a thread to execute the code if moveCursor: iNewPos = max(iPos, editor.positionFromLine(iLineEnd + 1)) editor.setSelectionStart(iNewPos) editor.setCurrentPos(iNewPos) if iNewPos >= iDocEnd and iLineEnd == editor.getLineCount( ) - 1: editor.newLine() editor.scrollCaret() if self.matplotlib_eventHandler and not self.matplotlib_enabled: if 'matplotlib' in block: self.interp.execute(init_matplotlib_eventHandler) self.matplotlib_enabled = True if isValue: res = self.interp.evaluate() if res is not None: err, result = res if not err: if self.bufferActive: self.changeMarkers(iMarker=self.m_finish, bufferID=bufferID) if result: self.stdout(result + '\n') else: self.changeMarkers(iMarker=self.m_error, bufferID=bufferID) self.outBuffer(result) else: res = self.interp.execute() if res is not None: err, result = res if not err and self.bufferActive: self.changeMarkers(iMarker=self.m_finish, bufferID=bufferID) else: self.changeMarkers(iMarker=self.m_error, bufferID=bufferID) self.outBuffer(result) if err: self.changeMarkers(iMarker=self.m_error, bufferID=bufferID) self.bufferActive = 0
def onMouseDwell(self, args): '''Show a call tip window about the current content of a selected variable''' if self.bufferBusy or self.interp.kernelBusy.isSet(): return if editor.callTipActive(): return p = editor.positionFromPoint(args['x'], args['y']) iStart = editor.getSelectionStart() iEnd = editor.getSelectionEnd() if iEnd != iStart and iStart <= p <= iEnd: if self.popupForSelectedExpression and iEnd - iStart > 1: expression = editor.getTextRange(iStart, iEnd) if expression == 'False': self.activeCalltip = False editor.callTipShow(iStart, 'set to True') elif expression == 'True': self.activeCalltip = True editor.callTipShow(iStart, 'set to False') elif not '\n' in expression: ret = self.interp.getCallTip(None, expression) if ret: element, nHighlight, calltip = ret self.activeCalltip = 'doc' editor.callTipShow(iStart, ''.join(calltip)) editor.callTipSetHlt(0, int(nHighlight)) else: iLineStart = editor.positionFromLine( editor.lineFromPosition(iStart)) var = editor.getTextRange(iStart, iEnd) line = editor.getTextRange(iLineStart, iEnd) if var == '.': autoCompleteList = self.interp.autoCompleteObject( self.getUncompleteLine(iStart + 1)) if autoCompleteList: editor.autoCSetSeparator(ord('\t')) editor.autoCSetIgnoreCase(False) editor.autoCSetCaseInsensitiveBehaviour(False) editor.autoCSetOrder(0) editor.autoCSetDropRestOfWord(True) editor.autoCShow(0, autoCompleteList) else: ret = self.interp.getCallTip(line, var) if ret: element, nHighlight, calltip = ret if element == var == 'False': self.activeCalltip = False editor.callTipShow(iStart, 'set to True') elif element == var == 'True': self.activeCalltip = True editor.callTipShow(iStart, 'set to False') else: self.activeCalltip = 'doc' editor.callTipShow(iStart, ''.join(calltip)) editor.callTipSetHlt(0, int(nHighlight)) elif self.popupForUnselectedVariable and iStart == iEnd and p >= 0: iLine = editor.lineFromPosition(p) line = editor.getLine(iLine) iLineStart = editor.positionFromLine(iLine) posInLine = p - iLineStart iWordEnd = 0 for iWordStart in range(posInLine, -1, -1): s = line[iWordStart] if not ('a' <= s <= 'z' or 'A' <= s <= 'Z' or '0' <= s <= '9' or s == '_'): iWordStart += 1 break if iWordStart <= posInLine: for iWordEnd in range(posInLine + 1, len(line)): s = line[iWordEnd] if not ('a' <= s <= 'z' or 'A' <= s <= 'Z' or '0' <= s <= '9' or s == '_'): iWordEnd -= 1 break var = line[iWordStart:iWordEnd + 1] if var: var = line[iWordStart:iWordEnd + 1] ret = self.interp.getCallTip(line[0:iWordEnd + 1], var) pos = iLineStart + iWordStart if ret: element, nHighlight, calltip = ret self.activeCalltip = 'doc' editor.callTipShow(pos, ''.join(calltip)) editor.callTipSetHlt(0, int(nHighlight))
def main(): if editor.getSelectionEmpty(): # user hasn't selected anything, hide cursor line start_line = end_line = editor.lineFromPosition(editor.getCurrentPos()) else: start_line, end_line = editor.getUserLineSelection() total_number_less_one_line = editor.getLineCount() - 1 # zero-based # recalculate which lines to hide as first and last line cannot be hide start_line = start_line if start_line > 0 else 1 end_line = end_line if total_number_less_one_line > end_line else end_line - 1 # calculate at which lines marker need to be placed marker_start_line = start_line - 1 if start_line > 0 else start_line marker_end_line = end_line + 1 if end_line < total_number_less_one_line else end_line # recalculate in case that marker(start/end)lines are not visible # either because they are part of a folding tree or already hidden while not editor.getLineVisible(marker_start_line): marker_start_line -= 1 if not editor.getLineVisible(marker_end_line): visible_line = editor.visibleFromDocLine(marker_end_line) marker_end_line = editor.docLineFromVisible(visible_line) # check if there is already a marker set at those lines marker_at_marker_start_line = editor.markerGet(marker_start_line) marker_at_marker_end_line = editor.markerGet(marker_end_line) marker_already_set = False if (marker_at_marker_start_line & MARK_HIDELINESBEGIN_MASK) == MARK_HIDELINESBEGIN_MASK: marker_type = 'start' marker_already_set = True elif (marker_at_marker_end_line & MARK_HIDELINESEND_MASK) == MARK_HIDELINESEND_MASK: marker_type = 'end' marker_already_set = True # already markers set - inform user if marker_already_set: if EXTEND_AUTOMATICALLY is False: answer = notepad.messageBox(( 'There can only be one {} marker per line\r\n' 'Should it be extended instead?\r\n' "If it shouldn't, it doesn't do anything").format(marker_type), 'Info!', 4) if EXTEND_AUTOMATICALLY or answer == MESSAGEBOXFLAGS.RESULTYES: if marker_type == 'start': _matching_marker_line = find_correspondig_marker( marker_start_line, MARK_HIDELINESEND_MASK) _start_marker_line_to_delete = marker_start_line _end_marker_line_to_delete = _matching_marker_line else: _matching_marker_line = find_correspondig_marker( marker_end_line, MARK_HIDELINESBEGIN_MASK) _start_marker_line_to_delete = _matching_marker_line _end_marker_line_to_delete = marker_end_line editor.markerDelete(_start_marker_line_to_delete, MARK_HIDELINESBEGIN) editor.markerDelete(_start_marker_line_to_delete, MARK_HIDELINESUNDERLINE) editor.markerDelete(_end_marker_line_to_delete, MARK_HIDELINESEND) else: return editor.hideLines(start_line, end_line) editor.markerAdd(marker_start_line, MARK_HIDELINESBEGIN) editor.markerAdd(marker_start_line, MARK_HIDELINESUNDERLINE) editor.markerAdd(marker_end_line, MARK_HIDELINESEND) editor.gotoLine(marker_start_line)