diff --git a/scripts/Samples/GotoLineCol.py b/scripts/Samples/GotoLineCol.py new file mode 100644 index 00000000..9da5cfed --- /dev/null +++ b/scripts/Samples/GotoLineCol.py @@ -0,0 +1,124 @@ +""" + Script: GotoLineCol.py + Utility: 1. Moves the cursor position to the specified line and column for a file in Notepad++. + Especially useful for inspecting data files in fixed-width record formats. + 2. Also, displays the character code (SBCS & LTR) in decimal and hex at the specified position. + Requires: Python Script plugin in Notepad++ + + Customizable parameters for the goToLineCol function call in main(): + bRepeatPrompt: Whether to repeat prompting when the specified number value is out of range + iEdgeBuffer: Ensures that the caret will be that many characters inside the left and right edges of the editor viewing area, when possible + iCaretHiliteDuration: Caret will be in Block mode for specified seconds + bCallTipAutoHide: Whether to hide the call tip automatically in sync when caret highlighting is turned off + bBraceHilite: Whether to use brace highlighting style for the character at the specified position. Automatically turns off when current line changes. + +Known Issues: 1. Character code display in the call tip is functional with SBCS (Single-Byte Character Sets) and LTR (left-to-right) direction. + With MBCS (Bulti-Bytes Character Sets) or RTL (right-to-left) direction, results will not be reliable. + 2. If iCaretHiliteDuration is set to a high value (>3 seconds), and the user tries to rerun the script + while the previous execution is still running, the Python Script plugin will display an error message: + "Another script is still running..." So set this parameter to 3 seconds or lower. + + Author: Shridhar Kumar + Date: 2019-08-15 +""" + +def main(): + goToLineCol(bRepeatPrompt = True, + iEdgeBuffer = 5, + iCaretHiliteDuration = 5, + bCallTipAutoHide = False, + bBraceHilite = True) + + +def getDisplayLineCol(): + iCurrLine = editor.lineFromPosition(editor.getCurrentPos()) + iCurrCol = editor.getCurrentPos() - editor.positionFromLine(iCurrLine) + return str(iCurrLine + 1), str(iCurrCol + 1) + +def promptValue(sInfoText, sTitleText, sDefaultVal, iMinVal, iMaxVal, sRangeError, bRepeatPrompt): + while True: + sNewVal = notepad.prompt(sInfoText, sTitleText, sDefaultVal) + if sNewVal == None: + return None + + try: + iNewVal = int(sNewVal) + if iMinVal <= iNewVal <= iMaxVal: + return iNewVal + else: + raise + except: + notepad.messageBox(sRangeError + '.\n\nYou specified: ' + sNewVal + + '\n\nPlease specify a number between ' + str(iMinVal) + ' and ' + str(iMaxVal) + '.', + 'Specified value is out of range') + if not bRepeatPrompt: + return None + + +def goToLineCol(bRepeatPrompt, iEdgeBuffer, iCaretHiliteDuration, bCallTipAutoHide, bBraceHilite): + import time + + sCurrLine, sCurrCol = getDisplayLineCol() + iMaxLines = editor.getLineCount() + + iNewLine = promptValue(sInfoText = 'Line number (between 1 and ' + str(iMaxLines) + '):', + sTitleText = 'Specify line number', + sDefaultVal = sCurrLine, + iMinVal = 1, + iMaxVal = iMaxLines, + sRangeError = 'File line count is only ' + str(iMaxLines), + bRepeatPrompt = bRepeatPrompt) + if iNewLine == None: + return + + # Get the character count plus 1 for the specified line + # Plus 1 is to account for the caret position at the end of the line, past all characters but before EOL/EOF + # Since lineLength already includes EOL, we just need to subtract 1 only when EOL is 2 chars. i.e., CRLF + # For the last line in file, there is no 2-character CRLF EOL; only a single character EOF. + iMaxCols = max(1, editor.lineLength(iNewLine - 1)) + if (editor.getEOLMode() == ENDOFLINE.CRLF) and (iNewLine < iMaxLines): + iMaxCols -= 1 + + iNewCol = promptValue(sInfoText = 'Column position (between 1 and ' + str(iMaxCols) + ') for line ' + str(iNewLine) + ':', + sTitleText = 'Specify column position', + sDefaultVal = sCurrCol, + iMinVal = 1, + iMaxVal = iMaxCols, + sRangeError = 'There are only ' + str(iMaxCols) + ' characters in line ' + str(iNewLine), + bRepeatPrompt = bRepeatPrompt) + + # Navigate to the specified position in the document + iLineStartPos = editor.positionFromLine(iNewLine - 1) + iNewPos = iLineStartPos + iNewCol - 1 + editor.ensureVisible(iNewLine - 1) + editor.gotoPos( min(iLineStartPos + iMaxCols, iNewPos + iEdgeBuffer) ) # Ensure that caret is 'iEdgeBuffer' characters inside right edge when possible + editor.gotoPos( max(iLineStartPos, iNewPos - iEdgeBuffer) ) # Ensure that caret is 'iEdgeBuffer' characters inside left edge when possible + editor.gotoPos(iNewPos) # Finally, move caret to the specified position + + # Obtain current caret style to restore it later on + currCS = editor.getCaretStyle() + + # Set the caret to block style to highlight the new position + editor.setCaretStyle(CARETSTYLE.BLOCK) + + # Display a call tip with the new line and column numbers with verification + # Also display the character code in decimal and hex + sCurrLine, sCurrCol = getDisplayLineCol() + editor.callTipShow(iNewPos, ' Line: ' + sCurrLine + + '\n Column: ' + sCurrCol + + '\nChar Code: ' + str(editor.getCharAt(iNewPos)) + ' [' + hex(editor.getCharAt(iNewPos)) + ']') + + if iCaretHiliteDuration > 0: + time.sleep(iCaretHiliteDuration) + + # Reset the caret style + editor.setCaretStyle(currCS) + + if bCallTipAutoHide: + editor.callTipCancel() + + if bBraceHilite: + editor.braceHighlight(iNewPos, iNewPos) + + +main()