Community
    • Login

    Feature Request: Show only line-final whitespace.

    Scheduled Pinned Locked Moved General Discussion
    whitespace
    28 Posts 7 Posters 16.6k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • guy038G
      guy038
      last edited by guy038

      Hi, @salviasage and All,

      A) Regarding your first question, I’m sorry, but I cannot do better :-( To go further on and add a real-time behavior, it needs the use of a language script, as the Python or Lua N++ plugins… and that task is over my technical skills ! May be some people, of the Community, could help you ?!

      However, I really surprised why you do care about seeing trailing blank characters. Indeed, you may, either, use :

      • The Edit > Blank operations > Trim Trailing Space option ( You can, even, define a shortcut, using the Shortcut Mapper )

      • The Macro > Trim Trailing Space and Save ( Alt + Shift + S ) which, automatically, save your file, without these unneeded blank characters

      B) Regarding your second question, presently, if you have a look to ? > Command Line Arguments…, there is not any -Macro argument, which could run a specific macro, on N++ startup. But, I know that some people, already did a request for such a feature !

      Best Regards,

      guy038

      1 Reply Last reply Reply Quote 0
      • Scott SumnerS
        Scott Sumner @SalviaSage
        last edited by

        @SalviaSage

        …doesn’t update itself realtime. Can this be made so it works in real time as you are typing?

        As I pointed out earlier in this thread, the regular expression solutions aren’t going to do this type of dynamic updating. If you are willing to install the Pythonscript plugin (currently only on 32-bit Notepad++), the script given in this thread is fairly easy to adapt to do what you wish, and it updates dynamically.

        I did this modification to come up with this new script, which I call EolWhitespaceHighlighter.py :

        try:
        
            EWH__dict
        
        except NameError:
        
            EWH__dict = dict()
        
            EWH__dict['indic_to_use'] = 10  # pick a free indicator number
        
            def indicatorOptionsSet(indicator_number, indicator_style, rgb_color_tup, alpha, outline_alpha, draw_under_text, which_editor=editor):
                which_editor.indicSetStyle(indicator_number, indicator_style)       # e.g. INDICATORSTYLE.ROUNDBOX
                which_editor.indicSetFore(indicator_number, rgb_color_tup)
                which_editor.indicSetAlpha(indicator_number, alpha)                 # integer
                which_editor.indicSetOutlineAlpha(indicator_number, outline_alpha)  # integer
                which_editor.indicSetUnder(indicator_number, draw_under_text)       # boolean
        
            for editorX in (editor1, editor2):
                indicatorOptionsSet(EWH__dict['indic_to_use'], INDICATORSTYLE.ROUNDBOX, (255,0,0), 100, 50, True, editorX)  # white box rimmed in "pale violet red 2"
        
            def EWH__fileIsCloned(file_name_to_test):
                retval = False
                clone_detect_dict = {}
                file_tup_list = notepad.getFiles()
                for tup in file_tup_list:
                    (filename, _, _, _) = tup
                    if filename not in clone_detect_dict:
                        clone_detect_dict[filename] = 0
                    else:
                        clone_detect_dict[filename] += 1
                        if filename == file_name_to_test: break
                if file_name_to_test in clone_detect_dict:
                    if clone_detect_dict[file_name_to_test] >= 1: retval = True
                return retval
        
            def EWH__fileIsClonedAndIsActiveInBothViews(file_name_to_test):
                retval = False
                if editor1 and editor2:
                    # both views are in use
                    if EWH__fileIsCloned(file_name_to_test):
                        curr_doc_index_main_view = notepad.getCurrentDocIndex(0)
                        curr_doc_index_2nd_view = notepad.getCurrentDocIndex(1)
                        main_view_active_doc_bool = False
                        secondary_view_active_doc_bool = False
                        file_tup_list = notepad.getFiles()
                        for tup in file_tup_list:
                            (filename, _, index_in_view, view_number) = tup
                            if filename == file_name_to_test:
                                if view_number == 0:
                                    if index_in_view == curr_doc_index_main_view:
                                        main_view_active_doc_bool = True
                                elif view_number == 1:
                                    if index_in_view == curr_doc_index_2nd_view:
                                        secondary_view_active_doc_bool = True
                                if main_view_active_doc_bool and secondary_view_active_doc_bool:
                                    retval = True
                                    break
                return retval
        
            def EWH__getViewableEditorAndRangeTupleListList(work_across_both_views):
                retval = []
                # retval looks like these examples:
                #  [ ( editor, [ (0, 1000), (2020, 3000) ] ) ]
                #  [ ( editor1, [ (0, 1000), (2020, 3000) ] ), ( editor2, [ (4000, 5000), (6020, 7000) ] ) ]
                def consolidate_range_tuple_list(range_tup_list):
                    sorted_range_tup_list = sorted(range_tup_list)  # sort criteria is first element of tuple in list
                    saved_2element_list = list(sorted_range_tup_list[0])
                    for (start, end) in sorted_range_tup_list:
                        if start <= saved_2element_list[1]:
                            saved_2element_list[1] = max(saved_2element_list[1], end)
                        else:
                            yield tuple(saved_2element_list)
                            saved_2element_list[0] = start
                            saved_2element_list[1] = end
                    yield tuple(saved_2element_list)
                def get_onscreen_pos_tup_list(which_editor):  # which_editor is editor1 or editor2 (or maybe even just plain editor)
                    # loosely based upon the N++ source for SmartHighlighter::highlightViewWithWord()
                    retval_tup_list = list()
                    temp_tup_list = []
                    MAXLINEHIGHLIGHT = 400
                    firstLine = which_editor.getFirstVisibleLine()
                    currentLine = firstLine
                    nbLineOnScreen = which_editor.linesOnScreen()
                    nrLines = min(nbLineOnScreen, MAXLINEHIGHLIGHT) + 1
                    lastLine = firstLine + nrLines
                    prevDocLineChecked = -1
                    break_out = False
                    while currentLine < lastLine:
                        docLine = which_editor.docLineFromVisible(currentLine)
                        if docLine != prevDocLineChecked:
                            prevDocLineChecked = docLine
                            startPos = which_editor.positionFromLine(docLine)
                            endPos = which_editor.positionFromLine(docLine + 1)
                            if endPos == -1:
                                endPos = which_editor.getTextLength() - 1
                                break_out = True
                            if endPos > startPos: temp_tup_list.append((startPos, endPos))
                            if break_out: break
                        currentLine += 1
                    if len(temp_tup_list) > 0:
                        retval_tup_list = list(consolidate_range_tuple_list(temp_tup_list))
                    return retval_tup_list
                both_views_open = True if editor1 and editor2 else False
                curr_file_active_in_both_views = EWH__fileIsClonedAndIsActiveInBothViews(notepad.getCurrentFilename()) if both_views_open else False
                if both_views_open:
                    ed1_range_tup_list = get_onscreen_pos_tup_list(editor1)
                    ed2_range_tup_list = get_onscreen_pos_tup_list(editor2)
                if curr_file_active_in_both_views:
                    range_tup_list = list(consolidate_range_tuple_list(ed1_range_tup_list + ed2_range_tup_list))
                    retval.append((editor, range_tup_list))
                elif both_views_open and work_across_both_views:
                    retval.append((editor1, ed1_range_tup_list))
                    retval.append((editor2, ed2_range_tup_list))
                else:
                    range_tup_list = get_onscreen_pos_tup_list(editor)
                    retval.append((editor, range_tup_list))
                return retval
        
            def EWH__callback_sci_UPDATEUI(args):
        
                for (editorX, pos_range_tuple_list) in EWH__getViewableEditorAndRangeTupleListList(True):
        
                    # clear out any existing highlighting in areas the user can currently see
                    for (start_pos, end_pos) in pos_range_tuple_list:
                        editorX.setIndicatorCurrent(EWH__dict['indic_to_use'])
                        editorX.indicatorClearRange(start_pos, end_pos - start_pos)
        
                    def eolws_hilite_regex_search_match_found_callback(m):
                        (span_start, span_end) = m.span()
                        editorX.setIndicatorCurrent(EWH__dict['indic_to_use'])
                        editorX.indicatorFillRange(span_start, span_end - span_start)
        
                    for (start_pos, end_pos) in pos_range_tuple_list:
                        editorX.research(
                            r'\h+$',
                            eolws_hilite_regex_search_match_found_callback,
                            0, #re.IGNORECASE,
                            start_pos,
                            end_pos
                            )
        
            editor.callbackSync(EWH__callback_sci_UPDATEUI, [SCINTILLANOTIFICATION.UPDATEUI])  # install callback
        
        else:
        
            editor.setSelectionMode(editor.getSelectionMode())  # force manual UPDATEUI to happen
        

        The key area that makes this script different from the one in that other thread is this little segment:

        for (start_pos, end_pos) in pos_range_tuple_list:
            editorX.research(
                r'\h+$',
                eolws_hilite_regex_search_match_found_callback,
                0, #re.IGNORECASE,
                start_pos,
                end_pos
                )
        

        Here you can see the regular expression \h+$ that matches trailing whitespace on a line.

        1 Reply Last reply Reply Quote 2
        • SalviaSageS
          SalviaSage
          last edited by

          Dear Scott Summer, I added your script to the startup.py and it is working perfectly. This is exactly the feature I want it, and now I got it. Thanks.

          1 Reply Last reply Reply Quote 1
          • SalviaSageS
            SalviaSage
            last edited by

            @dail

            Yo dail… According to this page: https://www.scintilla.org/ScintillaDoc.html#SCI_SETVIEWWS
            there is a visible only in indent command, which would only show these whitespace characters in the initial indentation area. and no where else.

            I am interested in doing that, I wrote the “SCWS_VISIBLEONLYININDENT” instead on your code above, but it didn’t work and syntax errored according to luascripts console.

            the error is right where I put this new syntax, so i don’t know if their documentation is wrong or what…

            and why are there two editor entries in there? Can you help me please? thx!

            dailD 1 Reply Last reply Reply Quote 0
            • dailD
              dail @SalviaSage
              last edited by

              @SalviaSage

              I wrote the “SCWS_VISIBLEONLYININDENT” instead on your code above,

              This option is supported starting with Scintilla v3.6.2 and newer, however Notepad++ is using Scintilla v3.5.6…so this is due to Notepad++ using an old version of Scintilla…and nothing LuaScript can do about it.

              and why are there two editor entries in there?

              If you “move” or “clone” a document within Notepad++ you get a split view and can edit two files at once…each of these is an “editor” thus there is an editor1 and editor2 variable. The editor variable always references the currently active editor.

              SalviaSageS 1 Reply Last reply Reply Quote 1
              • SalviaSageS
                SalviaSage @dail
                last edited by

                @dail said:

                This option is supported starting with Scintilla v3.6.2 and newer, however Notepad++ is using Scintilla v3.5.6…so this is due to Notepad++ using an old version of Scintilla…and nothing LuaScript can do about it.

                Thanks… I am crying a bucket right now :'( …

                1 Reply Last reply Reply Quote 0
                • SalviaSageS
                  SalviaSage
                  last edited by

                  I found this code:

                  editor.WhitespaceSize = 0
                  

                  basically, this hides the spaces indicator and not the tabs indicator.
                  Since tabs are only found at indents (or at least are supposed to be) we can see this symbol on indents
                  We can’t see the spaces symbol anywhere, but that’s okay. We will know it is spaces anyway, because if tab was used
                  then it would show.

                  Final result:
                  https://i.imgur.com/rHARxzF.jpg

                  satisfactory enough for me!

                  1 Reply Last reply Reply Quote 2
                  • dinkumoilD
                    dinkumoil
                    last edited by

                    I wrote a plugin that can be used to display whitespace used for indentation normally but after the first visible character, it is shown as dots and arrows. Its name is ExtSettings. You can download it >>> here <<<. It will also be available soon via PluginsAdmin.

                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post
                    The Community of users of the Notepad++ text editor.
                    Powered by NodeBB | Contributors