From ebb633072a3bb92597d1e33369c2203b178615ef Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 18 Jun 2017 14:41:13 -0300 Subject: [PATCH 001/160] Added the updates from the main repository Sublime Text Studio. --- Default (Linux).sublime-keymap | 2 +- Default (OSX).sublime-keymap | 2 +- Default (Windows).sublime-keymap | 2 +- EnhancementCommands.sublime-commands | 6 ++++++ README.md | 14 ++++++++++++++ wrap_lines_enhancement.py | 23 +++++++++++++++++++++++ 6 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 EnhancementCommands.sublime-commands create mode 100644 wrap_lines_enhancement.py diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index 7b60e25..26820a9 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -1,3 +1,3 @@ [ - { "keys": ["alt+q"], "command": "wrap_lines_plus" } + { "keys": ["alt+q"], "command": "wrap_lines_enhancement" } ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index a488ae9..ee70264 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -1,3 +1,3 @@ [ - { "keys": ["super+alt+q"], "command": "wrap_lines_plus" } + { "keys": ["super+alt+q"], "command": "wrap_lines_enhancement" } ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index 7b60e25..26820a9 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -1,3 +1,3 @@ [ - { "keys": ["alt+q"], "command": "wrap_lines_plus" } + { "keys": ["alt+q"], "command": "wrap_lines_enhancement" } ] diff --git a/EnhancementCommands.sublime-commands b/EnhancementCommands.sublime-commands new file mode 100644 index 0000000..2238380 --- /dev/null +++ b/EnhancementCommands.sublime-commands @@ -0,0 +1,6 @@ +[ + { "caption": "Wrap Plus: Wrap Lines at 65 chars", "command": "wrap_lines_enhancement", "args": { "width": 65 } }, + { "caption": "Wrap Plus: Wrap Lines at 70 chars", "command": "wrap_lines_enhancement", "args": { "width": 70 } }, + { "caption": "Wrap Plus: Wrap Lines at 72 chars", "command": "wrap_lines_enhancement", "args": { "width": 72 } }, + { "caption": "Wrap Plus: Wrap Lines at 80 chars", "command": "wrap_lines_enhancement", "args": { "width": 80 } }, +] diff --git a/README.md b/README.md index 4f6e577..49037ca 100644 --- a/README.md +++ b/README.md @@ -185,3 +185,17 @@ If you select a range of characters, *only* the lines that are selected will be ## Epilogue ## Wrap Plus handles a lot of situations that the stock Sublime word wrapper doesn't handle, but it's likely there are many situations where it doesn't work quite right. If you come across a problem, the immediate solution is to manually select the lines you want to wrap (this will constrain wrapping to just those lines). If you'd like, feel free to post an [issue](https://github.com/ehuss/Sublime-Wrap-Plus/issues) on the Github page. + + + +# Wrap Plus Enhanced + + +The file `wrap_lines_enhancement.py` is a wrapper around the default command `wrap_lines_plus` which +does add the following fix from the issue: + +(Wrap without loosing cursor position) +https://github.com/ehuss/Sublime-Wrap-Plus/issues/19 + + + diff --git a/wrap_lines_enhancement.py b/wrap_lines_enhancement.py new file mode 100644 index 0000000..513f51a --- /dev/null +++ b/wrap_lines_enhancement.py @@ -0,0 +1,23 @@ + + +import sublime, sublime_plugin + +class WrapLinesEnhancementCommand(sublime_plugin.TextCommand): + """ + Wrap without loosing cursor position + https://github.com/ehuss/Sublime-Wrap-Plus/issues/19 + + My workaround is simple. Create a new plugin with the following implementations: + https://github.com/ggutierrez + """ + + def run(self, edit, **kwargs): + + pos = self.view.sel()[0].begin() + + self.view.run_command('wrap_lines_plus', kwargs) + self.view.sel().clear() + self.view.sel().add(sublime.Region(pos)) + + + From 6c12e17479ba94a60069844cf688356733e0c987 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 11 Jul 2017 19:42:04 -0300 Subject: [PATCH 002/160] Added missing LICENSE.TXT --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 49037ca..91d4bb5 100644 --- a/README.md +++ b/README.md @@ -198,4 +198,7 @@ does add the following fix from the issue: https://github.com/ehuss/Sublime-Wrap-Plus/issues/19 +## License + +See the `LICENSE.txt` file under this repository. From 2ddcdd013a308916577e7d959c2e9a4eef8a9556 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 30 Aug 2017 09:34:34 -0300 Subject: [PATCH 003/160] Created new empty line types '\[\{\(' for the form: { Tese submetida ao Federal de \showfont } --- wrap_plus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index 7389dc4..9bd6df3 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -209,7 +209,7 @@ def OR(*args): def CONCAT(*args): return '(?:' + ''.join(args) + ')' -blank_line_pattern = re.compile(r'^[\t \n]*$') +blank_line_pattern = re.compile(r'^[\t \{\}\[\]\(\)\n]*$') # This doesn't always work, but seems decent. numbered_list = r'(?:(?:[0-9#]+[.)])+[\t ])' From 7af3e3b9ef02c9256f237c37dbbdf20a45ec6afd Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 30 Aug 2017 09:35:52 -0300 Subject: [PATCH 004/160] Created new paragraphs types '\[\{\(' for the form: \preambulo { \chooselang {Tese submetida ao Federal de \showfont} {Tese submetida ao asdfffffffffffffasd fdaf adsf df asfd asfd asdf sdf asdf adaf df ads fasd f Federal de \showfont} } --- wrap_plus.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 9bd6df3..adfa60e 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -219,10 +219,13 @@ def CONCAT(*args): latex_hack = r'(?:\\)(?!,|;|&|%|text|emph|cite|\w?(page)?ref|url|footnote|(La)*TeX)' rest_directive = r'(?:\.\.)' field_start = r'(?:[:@])' # rest, javadoc, jsdoc, etc. -new_paragraph_pattern = re.compile(r'^[\t ]*' + - OR(numbered_list, lettered_list, bullet_list, - field_start)) + +new_paragraph_pattern_string = r'^[\t ]*' + OR(numbered_list, lettered_list, bullet_list, field_start, r'\{', r'\[', r'\(') +# print( "pattern: " + new_paragraph_pattern_string ) + +new_paragraph_pattern = re.compile(new_paragraph_pattern_string) space_prefix_pattern = re.compile(r'^[ \t]*') + # XXX: Does not handle escaped colons in field name. fields = OR(r':[^:]+:', '@[a-zA-Z]+ ') field_pattern = re.compile(r'^([ \t]*)'+fields) # rest, javadoc, jsdoc, etc @@ -252,6 +255,9 @@ def _my_full_line(self, region): def _is_paragraph_start(self, line_r, line): # Certain patterns at the beginning of the line indicate this is the # beginning of a paragraph. + + # print( "line: " + str( line ) ) + # print( "new_paragraph_pattern.match(line): " + str( new_paragraph_pattern.match(line) ) ) return new_paragraph_pattern.match(line) != None def _is_paragraph_break(self, line_r, line, pure=False): From ca357b244205a53ecd0f94a62f44b305a21dd5a8 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 11 Sep 2017 07:40:55 -0300 Subject: [PATCH 005/160] Created the command Wrap Plus: Wrap Lines at ... chars (Ask) --- EnhancementCommands.sublime-commands | 6 ------ WrapPlus.sublime-commands | 12 ++++++++---- wrap_lines_enhancement.py | 16 ++++++++++++++++ wrap_plus.py | 3 ++- 4 files changed, 26 insertions(+), 11 deletions(-) delete mode 100644 EnhancementCommands.sublime-commands diff --git a/EnhancementCommands.sublime-commands b/EnhancementCommands.sublime-commands deleted file mode 100644 index 2238380..0000000 --- a/EnhancementCommands.sublime-commands +++ /dev/null @@ -1,6 +0,0 @@ -[ - { "caption": "Wrap Plus: Wrap Lines at 65 chars", "command": "wrap_lines_enhancement", "args": { "width": 65 } }, - { "caption": "Wrap Plus: Wrap Lines at 70 chars", "command": "wrap_lines_enhancement", "args": { "width": 70 } }, - { "caption": "Wrap Plus: Wrap Lines at 72 chars", "command": "wrap_lines_enhancement", "args": { "width": 72 } }, - { "caption": "Wrap Plus: Wrap Lines at 80 chars", "command": "wrap_lines_enhancement", "args": { "width": 80 } }, -] diff --git a/WrapPlus.sublime-commands b/WrapPlus.sublime-commands index 1d90553..b14e38d 100644 --- a/WrapPlus.sublime-commands +++ b/WrapPlus.sublime-commands @@ -1,6 +1,10 @@ [ - { - "caption": "Wrap Plus: Wrap Lines", - "command": "wrap_lines_plus" - } + { "caption": "Wrap Plus: Wrap Lines","command": "wrap_lines_plus" }, + { "caption": "Wrap Plus: Wrap Lines at ... chars (Ask)", "command": "wrap_lines_enhancement_ask" }, + + { "caption": "Wrap Plus: Wrap Lines at 65 chars", "command": "wrap_lines_enhancement", "args": { "width": 65 } }, + { "caption": "Wrap Plus: Wrap Lines at 70 chars", "command": "wrap_lines_enhancement", "args": { "width": 70 } }, + { "caption": "Wrap Plus: Wrap Lines at 72 chars", "command": "wrap_lines_enhancement", "args": { "width": 72 } }, + { "caption": "Wrap Plus: Wrap Lines at 80 chars", "command": "wrap_lines_enhancement", "args": { "width": 80 } }, + { "caption": "Wrap Plus: Wrap Lines at 100 chars", "command": "wrap_lines_enhancement", "args": { "width": 100 } }, ] diff --git a/wrap_lines_enhancement.py b/wrap_lines_enhancement.py index 513f51a..cc83cfc 100644 --- a/wrap_lines_enhancement.py +++ b/wrap_lines_enhancement.py @@ -20,4 +20,20 @@ def run(self, edit, **kwargs): self.view.sel().add(sublime.Region(pos)) +last_used_width = 80 + +class WrapLinesEnhancementAskCommand(sublime_plugin.TextCommand): + + def run(self, edit, **kwargs): + sublime.active_window().show_input_panel( + 'Provide wrapping width:', str( last_used_width ), + self.input_package, None, None + ) + + def input_package(self, width): + global last_used_width + + last_used_width = width + self.view.run_command('wrap_lines_plus', { 'width': int( width ) } ) + diff --git a/wrap_plus.py b/wrap_plus.py index adfa60e..44768df 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -474,7 +474,8 @@ def _determine_width(self, width): except TypeError: pass - width = self.view.settings().get('WrapPlus.wrap_width', width) + if width == 0: + width = self.view.settings().get('WrapPlus.wrap_width', width) # Value of 0 means 'automatic'. if width == 0: From 3fcbacaf3966b1180e5c958a5b7b968aa55643b9 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 16 Sep 2017 00:41:40 -0300 Subject: [PATCH 006/160] Added some debug messages to wrap_plus.py --- wrap_plus.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index 44768df..ee39f8b 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -459,12 +459,14 @@ def _determine_width(self, width): :returns: The maximum line width. """ + # print( "Here1, width: " + str( width ) ) if width == 0 and self.view.settings().get('wrap_width'): try: width = int(self.view.settings().get('wrap_width')) except TypeError: pass + # print( "Here1, width: " + str( width ) ) if width == 0 and self.view.settings().get('rulers'): # try and guess the wrap width from the ruler, if any try: @@ -474,6 +476,7 @@ def _determine_width(self, width): except TypeError: pass + # print( "Here1, width: " + str( width ) ) if width == 0: width = self.view.settings().get('WrapPlus.wrap_width', width) @@ -628,7 +631,8 @@ def run(self, edit, width=0): debug_start(self.view.settings().get('WrapPlus.debug', False)) debug('#########################################################################') self._width = self._determine_width(width) - debug('wrap width = %r', self._width) + + # print('wrap width = %r', self._width) self._determine_tab_size() self._determine_comment_style() From 9a4525b1d097545276801069145abe16ae206665 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 29 Sep 2017 14:27:38 -0300 Subject: [PATCH 007/160] Migrated the changes from User/Preferences to the Default package. --- Base File.sublime-settings | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 2db78a9..50397bc 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -1,9 +1,11 @@ { // If true, words longer than the wrap width will be split to ensure lines // are not longer than the wrap width. - "WrapPlus.break_long_words": true, + "WrapPlus.break_long_words": false, + // If true, will break on hyphens in compound words. - "WrapPlus.break_on_hyphens": true, + "WrapPlus.break_on_hyphens": false, + // Determines whether or not line endings are included in the line size: // - true: Always included. // - false: Never included. @@ -11,6 +13,7 @@ // Word Wrap) and Sublime's wrap column is not 0 (View -> Word Wrap // Column -> Automatic). "WrapPlus.include_line_endings": "auto" + // Set the wrap column, overriding Sublime's "wrap_width" if not 0. //"WrapPlus.wrap_width": 78 } From ffa9164ae289562867147941addc58be6e8d0d8b Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 6 Oct 2017 09:43:58 -0300 Subject: [PATCH 008/160] Added support for python multiline strings """ lines starts. --- wrap_plus.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index ee39f8b..a85e4ea 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -18,12 +18,13 @@ def is_quoted_string(scope_r, scope_name): return 'quoted' in scope_name or 'comment.block.documentation' in scope_name debug_enabled = False +# debug_enabled = True + time_start = 0 last_time = 0 def debug_start(enabled): - global debug_enabled, time_start, last_time - debug_enabled = enabled - if debug_enabled: + global time_start, last_time + if debug_enabled or enabled: time_start = time.time() last_time = time_start @@ -209,7 +210,7 @@ def OR(*args): def CONCAT(*args): return '(?:' + ''.join(args) + ')' -blank_line_pattern = re.compile(r'^[\t \{\}\[\]\(\)\n]*$') +blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') # This doesn't always work, but seems decent. numbered_list = r'(?:(?:[0-9#]+[.)])+[\t ])' @@ -220,7 +221,7 @@ def CONCAT(*args): rest_directive = r'(?:\.\.)' field_start = r'(?:[:@])' # rest, javadoc, jsdoc, etc. -new_paragraph_pattern_string = r'^[\t ]*' + OR(numbered_list, lettered_list, bullet_list, field_start, r'\{', r'\[', r'\(') +new_paragraph_pattern_string = r'^[\t ]*' + OR(numbered_list, lettered_list, bullet_list, field_start, r'\{') # print( "pattern: " + new_paragraph_pattern_string ) new_paragraph_pattern = re.compile(new_paragraph_pattern_string) @@ -629,7 +630,7 @@ def _extract_prefix(self, paragraph_r, lines, required_comment_prefix): def run(self, edit, width=0): debug_start(self.view.settings().get('WrapPlus.debug', False)) - debug('#########################################################################') + debug('\n\n#########################################################################') self._width = self._determine_width(width) # print('wrap width = %r', self._width) From bfb832ef7af8c2312c845f366f6e9cf8c000bddc Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 6 Nov 2017 11:08:48 -0200 Subject: [PATCH 009/160] Fixed redundant calls to view.settings() on wrap_plus.py --- wrap_plus.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index a85e4ea..688932a 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -645,6 +645,9 @@ def run(self, edit, width=0): debug('paragraphs is %r', paragraphs) + break_long_words = self.view.settings().get('WrapPlus.break_long_words', True) + break_on_hyphens = self.view.settings().get('WrapPlus.break_on_hyphens', True) + if paragraphs: # Use view selections to handle shifts from the replace() command. self.view.sel().clear() @@ -655,8 +658,6 @@ def run(self, edit, width=0): # the calls to replace(). for i, s in enumerate(self.view.sel()): paragraph_r, paragraph_lines, required_comment_prefix = paragraphs[i] - break_long_words = self.view.settings().get('WrapPlus.break_long_words', True) - break_on_hyphens = self.view.settings().get('WrapPlus.break_on_hyphens', True) wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) wrapper.width = self._width From e30c230fd8c9f5c672e661d7d2f3040d2c607ad6 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 6 Nov 2017 11:13:35 -0200 Subject: [PATCH 010/160] Fixed variable naming on wrap_plus.py --- wrap_plus.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 688932a..d2bdb51 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -651,13 +651,13 @@ def run(self, edit, width=0): if paragraphs: # Use view selections to handle shifts from the replace() command. self.view.sel().clear() - for r, l, p in paragraphs: - self.view.sel().add(r) + for region, lines, comment_prefix in paragraphs: + self.view.sel().add(region) # Regions fetched from view.sel() will shift appropriately with # the calls to replace(). - for i, s in enumerate(self.view.sel()): - paragraph_r, paragraph_lines, required_comment_prefix = paragraphs[i] + for index, selection in enumerate(self.view.sel()): + paragraph_r, paragraph_lines, required_comment_prefix = paragraphs[index] wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) wrapper.width = self._width @@ -689,28 +689,28 @@ def run(self, edit, width=0): lines[0] = orig_init_prefix + lines[0][len(init_prefix):] debug('new line is %r', lines[0]) if subsequent_prefix != orig_subsequent_prefix: - for i, line in enumerate(lines[1:]): - lines[i+1] = orig_subsequent_prefix + lines[i+1][len(subsequent_prefix):] + for index, line in enumerate(lines[1:]): + lines[index+1] = orig_subsequent_prefix + lines[index+1][len(subsequent_prefix):] txt = '\n'.join(lines) - replaced_txt = self.view.substr(s) + replaced_txt = self.view.substr(selection) # I can't decide if I prefer it to not make the modification # if there is no change (and thus don't mark an unmodified # file as modified), or if it's better to include a "non- # change" in the undo stack. - self.view.replace(edit, s, txt) + self.view.replace(edit, selection, txt) if replaced_txt != txt: debug('replaced text not the same:\noriginal=%r\nnew=%r', replaced_txt, txt) else: debug('replaced text is the same') # Move cursor below the last paragraph. - s = self.view.sel() - end = s[len(s)-1].end() + selection = self.view.sel() + end = selection[len(selection)-1].end() line = self.view.line(end) end = min(self.view.size(), line.end()+1) self.view.sel().clear() - r = sublime.Region(end) - self.view.sel().add(r) - self.view.show(r) + region = sublime.Region(end) + self.view.sel().add(region) + self.view.show(region) debug_end() From 5d0a150911453f3ec3f8eb77ae4ba32688fcbec5 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 6 Nov 2017 11:19:01 -0200 Subject: [PATCH 011/160] Created the function move_cursor_below_the_last_paragraph() --- wrap_plus.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index d2bdb51..30932a1 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -704,7 +704,9 @@ def run(self, edit, width=0): else: debug('replaced text is the same') - # Move cursor below the last paragraph. + self.move_cursor_below_the_last_paragraph() + + def move_cursor_below_the_last_paragraph(self): selection = self.view.sel() end = selection[len(selection)-1].end() line = self.view.line(end) From 6564b2024f015ff823645960986ba3785454e4c2 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 6 Nov 2017 11:22:48 -0200 Subject: [PATCH 012/160] Fixed redundant text wrapper object creations on wrap_plus.py --- wrap_plus.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 30932a1..c835704 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -648,6 +648,11 @@ def run(self, edit, width=0): break_long_words = self.view.settings().get('WrapPlus.break_long_words', True) break_on_hyphens = self.view.settings().get('WrapPlus.break_on_hyphens', True) + wrapper = textwrap.TextWrapper(break_long_words=break_long_words, + break_on_hyphens=break_on_hyphens) + wrapper.width = self._width + wrapper.expand_tabs = False + if paragraphs: # Use view selections to handle shifts from the replace() command. self.view.sel().clear() @@ -658,12 +663,10 @@ def run(self, edit, width=0): # the calls to replace(). for index, selection in enumerate(self.view.sel()): paragraph_r, paragraph_lines, required_comment_prefix = paragraphs[index] - wrapper = textwrap.TextWrapper(break_long_words=break_long_words, - break_on_hyphens=break_on_hyphens) - wrapper.width = self._width init_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_r, paragraph_lines, required_comment_prefix) orig_init_prefix = init_prefix orig_subsequent_prefix = subsequent_prefix + if orig_init_prefix or orig_subsequent_prefix: # Textwrap is somewhat limited. It doesn't recognize tabs # in prefixes. Unfortunately, this means we can't easily @@ -674,8 +677,6 @@ def run(self, edit, width=0): wrapper.initial_indent = init_prefix wrapper.subsequent_indent = subsequent_prefix - wrapper.expand_tabs = False - txt = '\n'.join(paragraph_lines) txt = txt.expandtabs(self._tab_width) txt = wrapper.fill(txt) From fd8c2aedc93502aa73196ab6032f863f893e49a0 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 6 Nov 2017 11:38:56 -0200 Subject: [PATCH 013/160] Split wrap_plus.py run() into several functions. --- wrap_plus.py | 98 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index c835704..0ffe094 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -425,8 +425,8 @@ def _find_paragraphs(self, sr): break - paragraph_r = sublime.Region(paragraph_start_pt, paragraph_end_pt) - result.append((paragraph_r, lines, view.required_comment_prefix)) + paragraph_region = sublime.Region(paragraph_start_pt, paragraph_end_pt) + result.append((paragraph_region, lines, view.required_comment_prefix)) if is_empty: break @@ -553,7 +553,7 @@ def _make_indent(self): # else: # return '\t' - def _extract_prefix(self, paragraph_r, lines, required_comment_prefix): + def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): # The comment prefix has already been stripped from the lines. # If the first line starts with a list-like thing, then that will be the initial prefix. initial_prefix = '' @@ -599,7 +599,7 @@ def _extract_prefix(self, paragraph_r, lines, required_comment_prefix): initial_prefix = '' subsequent_prefix = '' - pt = paragraph_r.begin() + pt = paragraph_region.begin() scope_r = self.view.extract_scope(pt) scope_name = self.view.scope_name(pt) if len(lines)==1 and is_quoted_string(scope_r, scope_name): @@ -662,51 +662,57 @@ def run(self, edit, width=0): # Regions fetched from view.sel() will shift appropriately with # the calls to replace(). for index, selection in enumerate(self.view.sel()): - paragraph_r, paragraph_lines, required_comment_prefix = paragraphs[index] - init_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_r, paragraph_lines, required_comment_prefix) - orig_init_prefix = init_prefix - orig_subsequent_prefix = subsequent_prefix - - if orig_init_prefix or orig_subsequent_prefix: - # Textwrap is somewhat limited. It doesn't recognize tabs - # in prefixes. Unfortunately, this means we can't easily - # differentiate between the initial and subsequent. This - # is a workaround. - init_prefix = orig_init_prefix.expandtabs(self._tab_width) - subsequent_prefix = orig_subsequent_prefix.expandtabs(self._tab_width) - wrapper.initial_indent = init_prefix - wrapper.subsequent_indent = subsequent_prefix - - txt = '\n'.join(paragraph_lines) - txt = txt.expandtabs(self._tab_width) - txt = wrapper.fill(txt) - - # Put the tabs back to the prefixes. - if orig_init_prefix or orig_subsequent_prefix: - if init_prefix != orig_subsequent_prefix or subsequent_prefix != orig_subsequent_prefix: - lines = txt.splitlines() - if init_prefix != orig_init_prefix: - debug('fix tabs %r', lines[0]) - lines[0] = orig_init_prefix + lines[0][len(init_prefix):] - debug('new line is %r', lines[0]) - if subsequent_prefix != orig_subsequent_prefix: - for index, line in enumerate(lines[1:]): - lines[index+1] = orig_subsequent_prefix + lines[index+1][len(subsequent_prefix):] - txt = '\n'.join(lines) - - replaced_txt = self.view.substr(selection) + paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] + text = self.hard_wrap_text(wrapper, paragraph_region, paragraph_lines, required_comment_prefix) + # I can't decide if I prefer it to not make the modification # if there is no change (and thus don't mark an unmodified # file as modified), or if it's better to include a "non- # change" in the undo stack. - self.view.replace(edit, selection, txt) - if replaced_txt != txt: - debug('replaced text not the same:\noriginal=%r\nnew=%r', replaced_txt, txt) - else: - debug('replaced text is the same') + self.view.replace(edit, selection, text) + self.print_text_replacements(text, selection) self.move_cursor_below_the_last_paragraph() + def hard_wrap_text(self, wrapper, paragraph_region, paragraph_lines, required_comment_prefix): + init_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_region, paragraph_lines, required_comment_prefix) + orig_init_prefix = init_prefix + orig_subsequent_prefix = subsequent_prefix + + if orig_init_prefix or orig_subsequent_prefix: + # Textwrap is somewhat limited. It doesn't recognize tabs + # in prefixes. Unfortunately, this means we can't easily + # differentiate between the initial and subsequent. This + # is a workaround. + init_prefix = orig_init_prefix.expandtabs(self._tab_width) + subsequent_prefix = orig_subsequent_prefix.expandtabs(self._tab_width) + wrapper.initial_indent = init_prefix + wrapper.subsequent_indent = subsequent_prefix + + text = '\n'.join(paragraph_lines) + text = text.expandtabs(self._tab_width) + text = wrapper.fill(text) + + # Put the tabs back to the prefixes. + if orig_init_prefix or orig_subsequent_prefix: + + if init_prefix != orig_subsequent_prefix or subsequent_prefix != orig_subsequent_prefix: + lines = text.splitlines() + + if init_prefix != orig_init_prefix: + debug('fix tabs %r', lines[0]) + lines[0] = orig_init_prefix + lines[0][len(init_prefix):] + debug('new line is %r', lines[0]) + + if subsequent_prefix != orig_subsequent_prefix: + + for index, line in enumerate(lines[1:]): + lines[index+1] = orig_subsequent_prefix + lines[index+1][len(subsequent_prefix):] + + text = '\n'.join(lines) + + return text + def move_cursor_below_the_last_paragraph(self): selection = self.view.sel() end = selection[len(selection)-1].end() @@ -717,3 +723,11 @@ def move_cursor_below_the_last_paragraph(self): self.view.sel().add(region) self.view.show(region) debug_end() + + def print_text_replacements(self, text, selection): + replaced_txt = self.view.substr(selection) + + if replaced_txt != text: + debug('replaced text not the same:\noriginal=%r\nnew=%r', replaced_txt, text) + else: + debug('replaced text is the same') From 9cc9ed4817266fa39f57a776271ec26f954ec715 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 6 Nov 2017 21:20:15 -0200 Subject: [PATCH 014/160] Implemented the function is_comma_separated_list() and partially implemented the semantic_line_wrap() call and some Unit Tests. --- wrap_plus.py | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 3 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 0ffe094..e87eca1 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -3,6 +3,7 @@ import textwrap import re import time +import unittest try: import Default.comment as comment except ImportError: @@ -210,7 +211,12 @@ def OR(*args): def CONCAT(*args): return '(?:' + ''.join(args) + ')' +max_words_in_comma_separated_list = 4 +list_of_words_pattern = re.compile(r'(?:^|\s)+\w+\s*(?!\w+)', re.MULTILINE) + blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') +whitespace_character = (" ", "\t") +word_separator_characters = ( ",", "." ) # This doesn't always work, but seems decent. numbered_list = r'(?:(?:[0-9#]+[.)])+[\t ])' @@ -663,7 +669,10 @@ def run(self, edit, width=0): # the calls to replace(). for index, selection in enumerate(self.view.sel()): paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] - text = self.hard_wrap_text(wrapper, paragraph_region, paragraph_lines, required_comment_prefix) + init_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_region, paragraph_lines, required_comment_prefix) + + # text = self.hard_wrap_text(wrapper, paragraph_lines, init_prefix, subsequent_prefix) + text = self.semantic_line_wrap(paragraph_lines, init_prefix, subsequent_prefix) # I can't decide if I prefer it to not make the modification # if there is no change (and thus don't mark an unmodified @@ -674,8 +683,117 @@ def run(self, edit, width=0): self.move_cursor_below_the_last_paragraph() - def hard_wrap_text(self, wrapper, paragraph_region, paragraph_lines, required_comment_prefix): - init_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_region, paragraph_lines, required_comment_prefix) + def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): + new_text = [init_prefix] + + is_allowed_to_wrap = False + is_possible_space = False + + text = ' '.join(paragraph_lines) + text_length = len(text) + accumulated_line = "" + + for index, character in enumerate(text): + + if is_possible_space and character in whitespace_character: + continue + + else: + is_possible_space = False + + accumulated_line_length = len( accumulated_line ) + + if accumulated_line_length > 10: + is_allowed_to_wrap = True + + if character in word_separator_characters and is_allowed_to_wrap \ + or accumulated_line_length >= self._width: + + if index + 2 < text_length: + + if not self.is_comma_separated_list(text, index): + + new_text.append(accumulated_line + character + "\n" + subsequent_prefix) + accumulated_line = "" + + is_possible_space = True + is_allowed_to_wrap = False + + else: + accumulated_line += character + + else: + accumulated_line += character + + else: + accumulated_line += character + + if len( accumulated_line ): + new_text.append(accumulated_line) + accumulated_line = "" + + return "".join(new_text) + + def is_comma_separated_list(self, text, index): + is_followed_by_space = text[index+1] in whitespace_character + + if is_followed_by_space: + text_length = len( text ) + current_index = index + + if self._is_comma_separated( text, index, False ): + return True + + if self._is_comma_separated( text, index, True ): + return True + + return False + + def _is_comma_separated(self, text, index, is_forward_search, recursive_level=1): + # print( "index: %d, is_forward_search: %s, recursive_level: %d" % ( index, str( is_forward_search ), recursive_level ) ) + + current_index = index + text_length = len( text ) - 1 + + if is_forward_search: + + def cut_out_comma_section(): + return text[ current_index:index+1 ] + + def next_element_condition(): + return index < text_length + + else: + + def cut_out_comma_section(): + return text[ index:current_index+1 ] + + def next_element_condition(): + return index > 0 + + while next_element_condition(): + index = index + 1 if is_forward_search else index - 1 + character = text[index] + # print( "character: " + str( character ) ) + + if character in word_separator_characters: + # print( "1text: " + cut_out_comma_section() ) + + # # Check whether there is a next comma which can a sequence on the list + # if recursive_level > 0: + + # if not self._is_comma_separated(text, index, is_forward_search, 0): + # return False + + results = list_of_words_pattern.findall( cut_out_comma_section() ) + # print( "1results: " + str( results ) ) + + if 0 < len( results ) < max_words_in_comma_separated_list: + return True + + return False + + def hard_wrap_text(self, wrapper, paragraph_lines, init_prefix, subsequent_prefix): orig_init_prefix = init_prefix orig_subsequent_prefix = subsequent_prefix @@ -731,3 +849,83 @@ def print_text_replacements(self, text, selection): debug('replaced text not the same:\noriginal=%r\nnew=%r', replaced_txt, text) else: debug('replaced text is the same') + + +def plugin_loaded(): + main() + pass + + +def main(): + runner = unittest.TextTestRunner() + runner.run( suite() ) + + +def suite(): + """ + Problem with sys.argv[1] when unittest module is in a script + https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script + + Is there a way to loop through and execute all of the functions in a Python class? + https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute-all-of-the-functions + + looping over all member variables of a class in python + https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python + """ + suite = unittest.TestSuite() + classes = [ WrapPlusUnitTests ] + + for _class in classes: + _object = _class() + + for methode_name in dir( _object ): + + if methode_name.lower().startswith( "test" ): + suite.addTest( WrapPlusUnitTests( methode_name ) ) + + return suite + + +class WrapPlusUnitTests(unittest.TestCase): + + def test_is_command_separated_list(self): + self.assertEqual( ['1', ' 2', ' 3', ' 4'], list_of_words_pattern.findall( "1, 2, 3, 4" ) ) + + def test_is_command_separated_list(self): + self.is_command_separated_list( "_, 1 2 3 4_ 5", 1, False ) + self.is_command_separated_list( "1, 2, 3, 4, 5", 1, True ) + self.is_command_separated_list( "1, 2, 3, 4, 5", 4, True ) + + self.is_command_separated_list( "1 2, 3, 4 5", 3, True ) + self.is_command_separated_list( "1 2, 3, 4 5", 6, True ) + self.is_command_separated_list( "1 2, 3_ 4 5", 3, False ) + + self.is_command_separated_list( "1 2, 3 4, 5", 3, True ) + self.is_command_separated_list( "1 2, 3 4, 5", 8, True ) + + def test_is_command_separated_list_upperbound(self): + self.is_command_separated_list( "1 2, 3 4 5 6, 7", 3, False ) + self.is_command_separated_list( "1 2, 3 4 5 6, 7", 12, False ) + + self.is_command_separated_list( "1 2, 3 4_5 6_ 7", 3, False ) + self.is_command_separated_list( "1 2, 3 4 5 6_ 7", 3, False ) + + self.is_command_separated_list( "1 2_ 3 4_5 6, 7", 12, False ) + self.is_command_separated_list( "1 2_ 3 4 5 6, 7", 12, False ) + + def test_is_command_separated_list_lowerbound(self): + self.is_command_separated_list( "1 2, 3 4_5 6, 7", 3, True ) + self.is_command_separated_list( "1 2, 3 4_5 6, 7", 12, True ) + + self.is_command_separated_list( "1 2, 3_4_5 6, 7", 3, True ) + self.is_command_separated_list( "1 2, 3_4_5 6, 7", 12, True ) + + self.is_command_separated_list( "1 2, 3_4_5_6, 7", 3, True ) + self.is_command_separated_list( "1 2, 3_4_5_6, 7", 12, True ) + + def is_command_separated_list(self, text, index, goal): + wrap_plus = WrapLinesPlusCommand( None ) + self.assertTrue( text[index] in word_separator_characters ) + self.assertEqual( goal, wrap_plus.is_comma_separated_list( text, index ) ) + + From 0932dfa5a89710937b11a2317d0e30499fb132db Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 6 Nov 2017 21:56:24 -0200 Subject: [PATCH 015/160] Created the initial unit tests for the function semantic_line_wrap --- wrap_plus.py | 93 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index e87eca1..f9c2641 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -711,7 +711,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): if index + 2 < text_length: - if not self.is_comma_separated_list(text, index): + if not self.is_comma_separated_list(text, index, True): new_text.append(accumulated_line + character + "\n" + subsequent_prefix) accumulated_line = "" @@ -734,23 +734,14 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): return "".join(new_text) - def is_comma_separated_list(self, text, index): + def is_comma_separated_list(self, text, index, is_forward_search, recursive_level=1): is_followed_by_space = text[index+1] in whitespace_character - if is_followed_by_space: - text_length = len( text ) - current_index = index + # print( "index: %3d, recursive_level: %3d, is_forward_search: %5s, is_followed_by_space: %5s" + # % ( index, recursive_level, str( is_forward_search ), str( is_followed_by_space ) ) ) - if self._is_comma_separated( text, index, False ): - return True - - if self._is_comma_separated( text, index, True ): - return True - - return False - - def _is_comma_separated(self, text, index, is_forward_search, recursive_level=1): - # print( "index: %d, is_forward_search: %s, recursive_level: %d" % ( index, str( is_forward_search ), recursive_level ) ) + if not is_followed_by_space: + return False current_index = index text_length = len( text ) - 1 @@ -763,6 +754,9 @@ def cut_out_comma_section(): def next_element_condition(): return index < text_length + def next_element_index(): + return index + 1 + else: def cut_out_comma_section(): @@ -771,8 +765,11 @@ def cut_out_comma_section(): def next_element_condition(): return index > 0 + def next_element_index(): + return index - 1 + while next_element_condition(): - index = index + 1 if is_forward_search else index - 1 + index = next_element_index() character = text[index] # print( "character: " + str( character ) ) @@ -782,7 +779,7 @@ def next_element_condition(): # # Check whether there is a next comma which can a sequence on the list # if recursive_level > 0: - # if not self._is_comma_separated(text, index, is_forward_search, 0): + # if not self.is_comma_separated_list(text, index, is_forward_search, 0): # return False results = list_of_words_pattern.findall( cut_out_comma_section() ) @@ -888,44 +885,60 @@ def suite(): class WrapPlusUnitTests(unittest.TestCase): + @classmethod + def setUpClass(self): + self.wrap_plus = WrapLinesPlusCommand( None ) + self.wrap_plus._width = 80 + def test_is_command_separated_list(self): self.assertEqual( ['1', ' 2', ' 3', ' 4'], list_of_words_pattern.findall( "1, 2, 3, 4" ) ) def test_is_command_separated_list(self): - self.is_command_separated_list( "_, 1 2 3 4_ 5", 1, False ) - self.is_command_separated_list( "1, 2, 3, 4, 5", 1, True ) - self.is_command_separated_list( "1, 2, 3, 4, 5", 4, True ) + self.is_comma_separated_list( "_, 1 2 3 4_ 5", 1, False ) + self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, True ) + self.is_comma_separated_list( "1, 2, 3, 4, 5", 4, True ) - self.is_command_separated_list( "1 2, 3, 4 5", 3, True ) - self.is_command_separated_list( "1 2, 3, 4 5", 6, True ) - self.is_command_separated_list( "1 2, 3_ 4 5", 3, False ) + self.is_comma_separated_list( "1 2, 3, 4 5", 3, True ) + self.is_comma_separated_list( "1 2, 3, 4 5", 6, True ) + self.is_comma_separated_list( "1 2, 3_ 4 5", 3, False ) - self.is_command_separated_list( "1 2, 3 4, 5", 3, True ) - self.is_command_separated_list( "1 2, 3 4, 5", 8, True ) + self.is_comma_separated_list( "1 2, 3 4, 5", 3, True ) + self.is_comma_separated_list( "1 2, 3 4, 5", 8, True ) def test_is_command_separated_list_upperbound(self): - self.is_command_separated_list( "1 2, 3 4 5 6, 7", 3, False ) - self.is_command_separated_list( "1 2, 3 4 5 6, 7", 12, False ) + self.is_comma_separated_list( "1 2, 3 4 5 6, 7", 3, False ) + self.is_comma_separated_list( "1 2, 3 4 5 6, 7", 12, False ) - self.is_command_separated_list( "1 2, 3 4_5 6_ 7", 3, False ) - self.is_command_separated_list( "1 2, 3 4 5 6_ 7", 3, False ) + self.is_comma_separated_list( "1 2, 3 4_5 6_ 7", 3, False ) + self.is_comma_separated_list( "1 2, 3 4 5 6_ 7", 3, False ) - self.is_command_separated_list( "1 2_ 3 4_5 6, 7", 12, False ) - self.is_command_separated_list( "1 2_ 3 4 5 6, 7", 12, False ) + self.is_comma_separated_list( "1 2_ 3 4_5 6, 7", 12, False ) + self.is_comma_separated_list( "1 2_ 3 4 5 6, 7", 12, False ) def test_is_command_separated_list_lowerbound(self): - self.is_command_separated_list( "1 2, 3 4_5 6, 7", 3, True ) - self.is_command_separated_list( "1 2, 3 4_5 6, 7", 12, True ) + self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3, True ) + self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 12, True ) - self.is_command_separated_list( "1 2, 3_4_5 6, 7", 3, True ) - self.is_command_separated_list( "1 2, 3_4_5 6, 7", 12, True ) + self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 3, True ) + self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 12, True ) - self.is_command_separated_list( "1 2, 3_4_5_6, 7", 3, True ) - self.is_command_separated_list( "1 2, 3_4_5_6, 7", 12, True ) + self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 3, True ) + self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 12, True ) - def is_command_separated_list(self, text, index, goal): - wrap_plus = WrapLinesPlusCommand( None ) + def is_comma_separated_list(self, text, index, goal): self.assertTrue( text[index] in word_separator_characters ) - self.assertEqual( goal, wrap_plus.is_comma_separated_list( text, index ) ) + self.assertEqual( goal, self.wrap_plus.is_comma_separated_list( text, index, True ) + or self.wrap_plus.is_comma_separated_list( text, index, False ) ) + + def test_semantic_line_wrap(self): + self.semantic_line_wrap( "1", "1" ) + self.semantic_line_wrap( "which will take, you quite some time", + "which will take,\nyou quite some time" ) + + self.semantic_line_wrap( "which will take, you, quite some time", + "which will take, you,\nquite some time" ) + + def semantic_line_wrap(self, initial_text, goal): + self.assertEqual( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ), goal ) From 4eb16e6cb4b36548e52ab73bc0bb9f3933ff38fb Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 6 Nov 2017 22:06:47 -0200 Subject: [PATCH 016/160] Fixed the semantic_line_wrap wrapping lines without spaces. --- wrap_plus.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index f9c2641..313395b 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -710,8 +710,10 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): or accumulated_line_length >= self._width: if index + 2 < text_length: + is_followed_by_space = text[index+1] in whitespace_character - if not self.is_comma_separated_list(text, index, True): + if is_followed_by_space \ + and not self.is_comma_separated_list(text, index, True): new_text.append(accumulated_line + character + "\n" + subsequent_prefix) accumulated_line = "" @@ -730,18 +732,13 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): if len( accumulated_line ): new_text.append(accumulated_line) - accumulated_line = "" + # print( "new_text: " + str( new_text ) ) return "".join(new_text) def is_comma_separated_list(self, text, index, is_forward_search, recursive_level=1): - is_followed_by_space = text[index+1] in whitespace_character - - # print( "index: %3d, recursive_level: %3d, is_forward_search: %5s, is_followed_by_space: %5s" - # % ( index, recursive_level, str( is_forward_search ), str( is_followed_by_space ) ) ) - - if not is_followed_by_space: - return False + # print( "index: %3d, recursive_level: %3d, is_forward_search: %5s" + # % ( index, recursive_level, str( is_forward_search ) ) ) current_index = index text_length = len( text ) - 1 @@ -938,6 +935,9 @@ def test_semantic_line_wrap(self): self.semantic_line_wrap( "which will take, you, quite some time", "which will take, you,\nquite some time" ) + self.semantic_line_wrap( "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime", + "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ) + def semantic_line_wrap(self, initial_text, goal): self.assertEqual( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ), goal ) From cf7ac07d59fb121f7632678a292f17fa2e41cd7f Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 7 Nov 2017 14:58:18 -0200 Subject: [PATCH 017/160] Fixed the semantic_line_wrap wrapping lines with long list of words --- wrap_plus.py | 198 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 121 insertions(+), 77 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 313395b..4ddcd21 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -216,7 +216,7 @@ def CONCAT(*args): blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') whitespace_character = (" ", "\t") -word_separator_characters = ( ",", "." ) +word_separator_characters = ( ",", ".", "?", "!", ":", ";" ) # This doesn't always work, but seems decent. numbered_list = r'(?:(?:[0-9#]+[.)])+[\t ])' @@ -686,12 +686,18 @@ def run(self, edit, width=0): def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): new_text = [init_prefix] - is_allowed_to_wrap = False - is_possible_space = False + is_allowed_to_wrap = False + is_possible_space = False + is_flushing_comma_list = False + is_comma_separated_list = False + is_to_force_flush_output = False - text = ' '.join(paragraph_lines) + text = ' '.join(paragraph_lines) text_length = len(text) - accumulated_line = "" + + accumulated_line = "" + line_start_index = 0 + comma_list_end_point = 0 for index, character in enumerate(text): @@ -701,6 +707,30 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): else: is_possible_space = False + # Skip the next characters as we already know they are a list. This is only called when + # the `comma_list_end_point` is lower than the `self._width`, otherwise the line will + # be immediately flushed + if comma_list_end_point > 0: + comma_list_end_point -= 1 + is_flushing_comma_list = True + + comma_list_size = index - line_start_index + line_remaining_size = self._width - comma_list_size + + # print( "is_flushing, index: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, comma_list_size, line_remaining_size, comma_list_end_point, character ) ) + + if not is_to_force_flush_output: + accumulated_line += character + + if comma_list_size >= self._width: + is_to_force_flush_output = True + + continue + + else: + is_flushing_comma_list = False + is_comma_separated_list = False + accumulated_line_length = len( accumulated_line ) if accumulated_line_length > 10: @@ -712,14 +742,24 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): if index + 2 < text_length: is_followed_by_space = text[index+1] in whitespace_character - if is_followed_by_space \ - and not self.is_comma_separated_list(text, index, True): + if is_followed_by_space: + + if not is_flushing_comma_list: + is_comma_separated_list, comma_list_end_point = self.is_comma_separated_list(text, index, line_start_index) + comma_list_end_point -= index - line_start_index + 3 - new_text.append(accumulated_line + character + "\n" + subsequent_prefix) - accumulated_line = "" + if ( comma_list_end_point > 0 \ + and not is_flushing_comma_list ) \ + or not is_comma_separated_list \ + or is_to_force_flush_output: - is_possible_space = True - is_allowed_to_wrap = False + new_text.append( accumulated_line + character + "\n" + subsequent_prefix ) + accumulated_line = "" + line_start_index = index + 1 + + is_possible_space = True + is_allowed_to_wrap = False + is_to_force_flush_output = False else: accumulated_line += character @@ -736,56 +776,56 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): # print( "new_text: " + str( new_text ) ) return "".join(new_text) - def is_comma_separated_list(self, text, index, is_forward_search, recursive_level=1): - # print( "index: %3d, recursive_level: %3d, is_forward_search: %5s" - # % ( index, recursive_level, str( is_forward_search ) ) ) + def is_comma_separated_list(self, text, index, line_start_index=0): + # print( "is_comma_separated_list, index: %3d, line_start_index: %d" % ( index, line_start_index ) ) - current_index = index - text_length = len( text ) - 1 + text_length = len( text ) - 1 + slice_start_index = index - if is_forward_search: + while index < text_length: + index = index + 1 + character = text[index] + # print( "character: " + str( character ) ) - def cut_out_comma_section(): - return text[ current_index:index+1 ] + if character in word_separator_characters \ + or index >= text_length: - def next_element_condition(): - return index < text_length + comma_section = text[ slice_start_index:index+1 ] + # print( "text: " + comma_section ) - def next_element_index(): - return index + 1 + results = list_of_words_pattern.findall( comma_section ) + results_count = len( results ) + # print( "results: " + str( results ) ) - else: + if 0 < results_count < max_words_in_comma_separated_list: - def cut_out_comma_section(): - return text[ index:current_index+1 ] + # Get the last match object + for match in list_of_words_pattern.finditer( comma_section ): + pass - def next_element_condition(): - return index > 0 + match_end = match.end(0) + possible_match_end = 0 - def next_element_index(): - return index - 1 + # `line_start_index` always greater than `index`, like 50 - 20 = 30 + # 50, 20 = 30, 80 - 30 = 50, 50 - 10 = 40 + line_remaining_size = self._width - ( index - line_start_index ) - match_end - while next_element_condition(): - index = next_element_index() - character = text[index] - # print( "character: " + str( character ) ) + # print( "line_remaining_size: " + str( line_remaining_size ) ) + # print( "match_end: " + str( match_end ) ) - if character in word_separator_characters: - # print( "1text: " + cut_out_comma_section() ) + is_there_new_commas, possible_match_end = self.is_comma_separated_list(text, index, line_start_index + match_end) + # print( "possible_match_end: " + str( possible_match_end ) ) - # # Check whether there is a next comma which can a sequence on the list - # if recursive_level > 0: + if possible_match_end > 0: + return True, possible_match_end + match_end - # if not self.is_comma_separated_list(text, index, is_forward_search, 0): - # return False + # print( "slice_start_index - line_start_index + match_end: " + str( slice_start_index - line_start_index + match_end ) ) + return True, slice_start_index - line_start_index + match_end - results = list_of_words_pattern.findall( cut_out_comma_section() ) - # print( "1results: " + str( results ) ) - - if 0 < len( results ) < max_words_in_comma_separated_list: - return True + else: + return False, 0 - return False + return False, 0 def hard_wrap_text(self, wrapper, paragraph_lines, init_prefix, subsequent_prefix): orig_init_prefix = init_prefix @@ -846,8 +886,17 @@ def print_text_replacements(self, text, selection): def plugin_loaded(): - main() pass + # print( "\n\n" ) + # main() + + # wrap_plus = WrapLinesPlusCommand( None ) + # wrap_plus._width = 80 + # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "which will not more take, you quite oh the time, some time, more time, the time, per time" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "few languages closely related. On this case, C, C++, Java, Pawn, etc. more over break this line" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "", "" ) def main(): @@ -888,57 +937,52 @@ def setUpClass(self): self.wrap_plus._width = 80 def test_is_command_separated_list(self): - self.assertEqual( ['1', ' 2', ' 3', ' 4'], list_of_words_pattern.findall( "1, 2, 3, 4" ) ) - - def test_is_command_separated_list(self): - self.is_comma_separated_list( "_, 1 2 3 4_ 5", 1, False ) self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, True ) - self.is_comma_separated_list( "1, 2, 3, 4, 5", 4, True ) - - self.is_comma_separated_list( "1 2, 3, 4 5", 3, True ) - self.is_comma_separated_list( "1 2, 3, 4 5", 6, True ) - self.is_comma_separated_list( "1 2, 3_ 4 5", 3, False ) - - self.is_comma_separated_list( "1 2, 3 4, 5", 3, True ) - self.is_comma_separated_list( "1 2, 3 4, 5", 8, True ) + self.is_comma_separated_list( "1_ 2, 3, 4_ 5", 4, True ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4, True ) + self.is_comma_separated_list( "1_ 2, 3_ 4, 5", 4, True ) def test_is_command_separated_list_upperbound(self): - self.is_comma_separated_list( "1 2, 3 4 5 6, 7", 3, False ) - self.is_comma_separated_list( "1 2, 3 4 5 6, 7", 12, False ) - - self.is_comma_separated_list( "1 2, 3 4_5 6_ 7", 3, False ) - self.is_comma_separated_list( "1 2, 3 4 5 6_ 7", 3, False ) - - self.is_comma_separated_list( "1 2_ 3 4_5 6, 7", 12, False ) - self.is_comma_separated_list( "1 2_ 3 4 5 6, 7", 12, False ) + self.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1, False ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6, 7", 4, False ) + self.is_comma_separated_list( "1_ 2, 3_ 4__5 6_ 7", 4, False ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6_ 7", 4, False ) def test_is_command_separated_list_lowerbound(self): self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3, True ) - self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 12, True ) - self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 3, True ) - self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 12, True ) - self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 3, True ) - self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 12, True ) def is_comma_separated_list(self, text, index, goal): self.assertTrue( text[index] in word_separator_characters ) - self.assertEqual( goal, self.wrap_plus.is_comma_separated_list( text, index, True ) - or self.wrap_plus.is_comma_separated_list( text, index, False ) ) + self.assertEqual( goal, self.wrap_plus.is_comma_separated_list( text, index, True )[0] + or self.wrap_plus.is_comma_separated_list( text, index, False )[0] ) - def test_semantic_line_wrap(self): + def test_semantic_line_wrap_simple_sentences(self): self.semantic_line_wrap( "1", "1" ) self.semantic_line_wrap( "which will take, you quite some time", "which will take,\nyou quite some time" ) self.semantic_line_wrap( "which will take, you, quite some time", - "which will take, you,\nquite some time" ) + "which will take,\nyou, quite some time" ) + def test_semantic_line_wrap_long_word(self): self.semantic_line_wrap( "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime", "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ) + def test_semantic_line_wrap_ending_with_comma_list(self): + self.semantic_line_wrap( "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc.", + "you still only configuring a few languages closely related.\nOn this case, C, C++, Java, Pawn, etc." ) + + def test_semantic_line_wrap_with_comma_list_on_the_middle(self): + self.semantic_line_wrap( "which will not more take, you quite oh the time, some time, more time, the time, per time", + "which will not more take,\nyou quite oh the time,\nsome time, more time, the time, per time" ) + + def test_semantic_line_wrap_with_comma_list_on_the_end(self): + self.semantic_line_wrap( "few languages close related. On this case, C, C++, Java, Pawn, etc. more over break this line", + "few languages close related.\nOn this case, C, C++, Java, Pawn, etc.\nmore over break this line" ) + def semantic_line_wrap(self, initial_text, goal): - self.assertEqual( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ), goal ) + self.assertEqual( goal, self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) From 0c219159d5864483d6b1cd23528406d7615b141d Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 7 Nov 2017 16:44:31 -0200 Subject: [PATCH 018/160] Fixed long words not being wrapped at the end of the line. --- wrap_plus.py | 85 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 4ddcd21..e08df3a 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -211,10 +211,12 @@ def OR(*args): def CONCAT(*args): return '(?:' + ''.join(args) + ')' +blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') max_words_in_comma_separated_list = 4 -list_of_words_pattern = re.compile(r'(?:^|\s)+\w+\s*(?!\w+)', re.MULTILINE) -blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') +list_of_words_pattern = re.compile(r'(?:^|\s)+[^ ]+', re.MULTILINE) +next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) + whitespace_character = (" ", "\t") word_separator_characters = ( ",", ".", "?", "!", ":", ";" ) @@ -700,6 +702,8 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): comma_list_end_point = 0 for index, character in enumerate(text): + accumulated_line_length = len( accumulated_line ) + next_word_length = self.peek_next_word_length( index, text ) if is_possible_space and character in whitespace_character: continue @@ -715,29 +719,39 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): is_flushing_comma_list = True comma_list_size = index - line_start_index - line_remaining_size = self._width - comma_list_size + line_remaining_size = self._width - 1 - comma_list_size - # print( "is_flushing, index: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, comma_list_size, line_remaining_size, comma_list_end_point, character ) ) + # print( "is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, line_remaining_size, comma_list_end_point, character ) ) if not is_to_force_flush_output: - accumulated_line += character - if comma_list_size >= self._width: + if accumulated_line_length + next_word_length >= self._width - 1: + # print( "Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_to_force_flush_output = True - continue + # Current character is a whitespace, but it must the the next, so fix the index + index -= 1 + + else: + accumulated_line += character + continue else: is_flushing_comma_list = False is_comma_separated_list = False - accumulated_line_length = len( accumulated_line ) - if accumulated_line_length > 10: is_allowed_to_wrap = True - if character in word_separator_characters and is_allowed_to_wrap \ - or accumulated_line_length >= self._width: + if accumulated_line_length + next_word_length >= self._width - 1: + is_to_force_flush_output = True + + # Current character is a whitespace, but it must the the next, so fix the index + index -= 1 + + if ( character in word_separator_characters \ + and is_allowed_to_wrap ) \ + or is_to_force_flush_output: if index + 2 < text_length: is_followed_by_space = text[index+1] in whitespace_character @@ -750,8 +764,11 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): if ( comma_list_end_point > 0 \ and not is_flushing_comma_list ) \ - or not is_comma_separated_list \ - or is_to_force_flush_output: + or not is_comma_separated_list \ + or is_to_force_flush_output: + + if character in whitespace_character: + character = "" new_text.append( accumulated_line + character + "\n" + subsequent_prefix ) accumulated_line = "" @@ -776,21 +793,37 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): # print( "new_text: " + str( new_text ) ) return "".join(new_text) + def peek_next_word_length(self, index, text): + match = next_word_pattern.match( text, index ) + + if match: + next_word = match.group(0) + + # print( "next_word: %s" % next_word ) + return len( next_word ) + + return 0 + def is_comma_separated_list(self, text, index, line_start_index=0): # print( "is_comma_separated_list, index: %3d, line_start_index: %d" % ( index, line_start_index ) ) + next_character = " " text_length = len( text ) - 1 slice_start_index = index while index < text_length: index = index + 1 character = text[index] - # print( "character: " + str( character ) ) - if character in word_separator_characters \ + if index + 1 < text_length: + next_character = text[index+1] + + # print( "character: %s, next_character: %s" % ( character, next_character ) ) + + if character in word_separator_characters and next_character in whitespace_character \ or index >= text_length: - comma_section = text[ slice_start_index:index+1 ] + comma_section = text[ slice_start_index+1:index+1 ] # print( "text: " + comma_section ) results = list_of_words_pattern.findall( comma_section ) @@ -808,7 +841,7 @@ def is_comma_separated_list(self, text, index, line_start_index=0): # `line_start_index` always greater than `index`, like 50 - 20 = 30 # 50, 20 = 30, 80 - 30 = 50, 50 - 10 = 40 - line_remaining_size = self._width - ( index - line_start_index ) - match_end + line_remaining_size = self._width - 1 - ( index - line_start_index ) - match_end # print( "line_remaining_size: " + str( line_remaining_size ) ) # print( "match_end: " + str( match_end ) ) @@ -887,16 +920,17 @@ def print_text_replacements(self, text, selection): def plugin_loaded(): pass - # print( "\n\n" ) - # main() + print( "\n\n" ) + main() - # wrap_plus = WrapLinesPlusCommand( None ) - # wrap_plus._width = 80 + wrap_plus = WrapLinesPlusCommand( None ) + wrap_plus._width = 80 # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) # wrap_plus.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "which will not more take, you quite oh the time, some time, more time, the time, per time" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "few languages closely related. On this case, C, C++, Java, Pawn, etc. more over break this line" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ], "", "" ) def main(): @@ -982,6 +1016,15 @@ def test_semantic_line_wrap_with_comma_list_on_the_end(self): self.semantic_line_wrap( "few languages close related. On this case, C, C++, Java, Pawn, etc. more over break this line", "few languages close related.\nOn this case, C, C++, Java, Pawn, etc.\nmore over break this line" ) + def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): + self.semantic_line_wrap( "For all other languages you still need to find out another source code " + "formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/" + "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}", + + "For all other languages you still need to find out another source " + "code\nformatter tool,\nwhich will be certainly\nlimited\\footnote{\\url{https://stackoverflow.com/" + "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ) + def semantic_line_wrap(self, initial_text, goal): self.assertEqual( goal, self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) From 9af0cb984867b1208dadfcdaebe04a27681d6cab Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 7 Nov 2017 17:03:49 -0200 Subject: [PATCH 019/160] Fixed the initial_prefix being ignored when calculating the line lenght. --- wrap_plus.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index e08df3a..b6d48a0 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -687,6 +687,7 @@ def run(self, edit, width=0): def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): new_text = [init_prefix] + init_prefix_length = len( init_prefix ) is_allowed_to_wrap = False is_possible_space = False @@ -725,7 +726,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): if not is_to_force_flush_output: - if accumulated_line_length + next_word_length >= self._width - 1: + if accumulated_line_length + next_word_length + init_prefix_length >= self._width - 1: # print( "Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_to_force_flush_output = True @@ -743,7 +744,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): if accumulated_line_length > 10: is_allowed_to_wrap = True - if accumulated_line_length + next_word_length >= self._width - 1: + if accumulated_line_length + next_word_length + init_prefix_length >= self._width - 1: is_to_force_flush_output = True # Current character is a whitespace, but it must the the next, so fix the index @@ -767,6 +768,9 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): or not is_comma_separated_list \ or is_to_force_flush_output: + # It is not the first line anymore, now we need to care about the `subsequent_prefix` length + init_prefix_length = len( subsequent_prefix ) + if character in whitespace_character: character = "" @@ -921,7 +925,7 @@ def print_text_replacements(self, text, selection): def plugin_loaded(): pass print( "\n\n" ) - main() + # main() wrap_plus = WrapLinesPlusCommand( None ) wrap_plus._width = 80 @@ -931,6 +935,8 @@ def plugin_loaded(): # wrap_plus.semantic_line_wrap( [ "few languages closely related. On this case, C, C++, Java, Pawn, etc. more over break this line" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, which will be certainly limited and still need to configure all over again." ], " ", " " ) + wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, which will be certainly limited and still need to configure all over again." ], " ", " " ) def main(): @@ -967,6 +973,7 @@ class WrapPlusUnitTests(unittest.TestCase): @classmethod def setUpClass(self): + self.maxDiff = None self.wrap_plus = WrapLinesPlusCommand( None ) self.wrap_plus._width = 80 @@ -1025,7 +1032,28 @@ def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): "code\nformatter tool,\nwhich will be certainly\nlimited\\footnote{\\url{https://stackoverflow.com/" "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ) + def test_semantic_line_wrap_with_initial_indentation(self): + self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " + "which will be certainly limited and still need to configure all over again.", " ", " " ], + + " For all other languages you still need to find out another source code f\n" + " tool, which will be certainly limited and still need to configure all over\n" + " again." ) + + def test_semantic_line_wrap_with_initial_indentation(self): + self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " + "which will be certainly limited and still need to configure all over again.", " ", " " ], + + " For all other languages you still need to find out another source code f\n" + " tool, which will be certainly limited and still need to configure all over\n" + " again." ) + def semantic_line_wrap(self, initial_text, goal): - self.assertEqual( goal, self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) + + if isinstance( initial_text, list ): + self.assertEqual( goal, self.wrap_plus.semantic_line_wrap( [initial_text[0]], initial_text[1], initial_text[2] ) ) + + else: + self.assertEqual( goal, self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) From 8eba007c8d5b09adc7abc8d7911293f2d179de63 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 7 Nov 2017 18:41:11 -0200 Subject: [PATCH 020/160] Fixed line not wrapping after flushing a full line. --- wrap_plus.py | 99 ++++++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index b6d48a0..62e981e 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -689,11 +689,10 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): new_text = [init_prefix] init_prefix_length = len( init_prefix ) - is_allowed_to_wrap = False is_possible_space = False is_flushing_comma_list = False is_comma_separated_list = False - is_to_force_flush_output = False + is_flushing_accumalated_line = False text = ' '.join(paragraph_lines) text_length = len(text) @@ -717,56 +716,60 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): # be immediately flushed if comma_list_end_point > 0: comma_list_end_point -= 1 - is_flushing_comma_list = True comma_list_size = index - line_start_index - line_remaining_size = self._width - 1 - comma_list_size + line_remaining_size = self._width - comma_list_size - # print( "is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, line_remaining_size, comma_list_end_point, character ) ) + # print( "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, line_remaining_size, comma_list_end_point, character ) ) - if not is_to_force_flush_output: + if not is_flushing_accumalated_line: - if accumulated_line_length + next_word_length + init_prefix_length >= self._width - 1: - # print( "Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) - is_to_force_flush_output = True + if accumulated_line_length + next_word_length + init_prefix_length > self._width: + # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) + is_flushing_accumalated_line = True # Current character is a whitespace, but it must the the next, so fix the index index -= 1 else: accumulated_line += character + + is_flushing_comma_list = True continue else: is_flushing_comma_list = False is_comma_separated_list = False - if accumulated_line_length > 10: - is_allowed_to_wrap = True + if not is_flushing_accumalated_line \ + and accumulated_line_length + next_word_length + init_prefix_length > self._width: - if accumulated_line_length + next_word_length + init_prefix_length >= self._width - 1: - is_to_force_flush_output = True + # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) + is_flushing_accumalated_line = True # Current character is a whitespace, but it must the the next, so fix the index index -= 1 - if ( character in word_separator_characters \ - and is_allowed_to_wrap ) \ - or is_to_force_flush_output: + # print( "semantic_line_wrap, character: %s " % ( character ) ) + + if character in word_separator_characters \ + or is_flushing_accumalated_line: if index + 2 < text_length: is_followed_by_space = text[index+1] in whitespace_character if is_followed_by_space: - if not is_flushing_comma_list: + if character in word_separator_characters \ + and not is_flushing_comma_list: + is_comma_separated_list, comma_list_end_point = self.is_comma_separated_list(text, index, line_start_index) comma_list_end_point -= index - line_start_index + 3 if ( comma_list_end_point > 0 \ and not is_flushing_comma_list ) \ or not is_comma_separated_list \ - or is_to_force_flush_output: + or is_flushing_accumalated_line: # It is not the first line anymore, now we need to care about the `subsequent_prefix` length init_prefix_length = len( subsequent_prefix ) @@ -779,8 +782,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): line_start_index = index + 1 is_possible_space = True - is_allowed_to_wrap = False - is_to_force_flush_output = False + is_flushing_accumalated_line = False else: accumulated_line += character @@ -794,7 +796,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): if len( accumulated_line ): new_text.append(accumulated_line) - # print( "new_text: " + str( new_text ) ) + # print( "semantic_line_wrap, new_text: " + str( new_text ) ) return "".join(new_text) def peek_next_word_length(self, index, text): @@ -822,17 +824,17 @@ def is_comma_separated_list(self, text, index, line_start_index=0): if index + 1 < text_length: next_character = text[index+1] - # print( "character: %s, next_character: %s" % ( character, next_character ) ) + # print( "is_comma_separated_list, character: %s, next_character: %s" % ( character, next_character ) ) if character in word_separator_characters and next_character in whitespace_character \ or index >= text_length: comma_section = text[ slice_start_index+1:index+1 ] - # print( "text: " + comma_section ) + # print( "is_comma_separated_list, text: " + comma_section ) results = list_of_words_pattern.findall( comma_section ) results_count = len( results ) - # print( "results: " + str( results ) ) + # print( "is_comma_separated_list, results: " + str( results ) ) if 0 < results_count < max_words_in_comma_separated_list: @@ -845,18 +847,18 @@ def is_comma_separated_list(self, text, index, line_start_index=0): # `line_start_index` always greater than `index`, like 50 - 20 = 30 # 50, 20 = 30, 80 - 30 = 50, 50 - 10 = 40 - line_remaining_size = self._width - 1 - ( index - line_start_index ) - match_end + line_remaining_size = self._width - ( index - line_start_index ) - match_end - # print( "line_remaining_size: " + str( line_remaining_size ) ) - # print( "match_end: " + str( match_end ) ) + # print( "is_comma_separated_list, line_remaining_size: " + str( line_remaining_size ) ) + # print( "is_comma_separated_list, match_end: " + str( match_end ) ) is_there_new_commas, possible_match_end = self.is_comma_separated_list(text, index, line_start_index + match_end) - # print( "possible_match_end: " + str( possible_match_end ) ) + # print( "is_comma_separated_list, possible_match_end: " + str( possible_match_end ) ) if possible_match_end > 0: return True, possible_match_end + match_end - # print( "slice_start_index - line_start_index + match_end: " + str( slice_start_index - line_start_index + match_end ) ) + # print( "is_comma_separated_list, slice_start_index - line_start_index + match_end: " + str( slice_start_index - line_start_index + match_end ) ) return True, slice_start_index - line_start_index + match_end else: @@ -925,18 +927,17 @@ def print_text_replacements(self, text, selection): def plugin_loaded(): pass print( "\n\n" ) - # main() + main() - wrap_plus = WrapLinesPlusCommand( None ) - wrap_plus._width = 80 + # wrap_plus = WrapLinesPlusCommand( None ) + # wrap_plus._width = 80 # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) # wrap_plus.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "which will not more take, you quite oh the time, some time, more time, the time, per time" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "few languages closely related. On this case, C, C++, Java, Pawn, etc. more over break this line" ], "", "" ) - # wrap_plus.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ], "", "" ) - # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, which will be certainly limited and still need to configure all over again." ], " ", " " ) - wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, which will be certainly limited and still need to configure all over again." ], " ", " " ) + # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, which" ], " ", " " ) def main(): @@ -1028,25 +1029,33 @@ def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): "formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/" "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}", - "For all other languages you still need to find out another source " - "code\nformatter tool,\nwhich will be certainly\nlimited\\footnote{\\url{https://stackoverflow.com/" + "For all other languages you still need to find out another source code " + "formatter\ntool,\nwhich will be certainly\nlimited\\footnote{\\url{https://stackoverflow.com/" "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ) - def test_semantic_line_wrap_with_initial_indentation(self): - self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " - "which will be certainly limited and still need to configure all over again.", " ", " " ], + def test_semantic_line_wrap_with_80_characters(self): + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + "few languages close related.\nOn this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program,\nassure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) - " For all other languages you still need to find out another source code f\n" - " tool, which will be certainly limited and still need to configure all over\n" - " again." ) + def test_semantic_line_wrap_with_79_characters(self): + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + "few languages close related.\nOn this case, C, C++, Java, Pawn, if, you, already, had, written, the, program,\nassure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) + + def test_semantic_line_wrap_with_81_characters(self): + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprogram, assure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) + + def test_semantic_line_wrap_with_81_characters_on_list_flusing(self): + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprograms, assure, everything, is, under, versioning, control, system, and,\nbroke, everything, etc.\nmore over break this line" ) def test_semantic_line_wrap_with_initial_indentation(self): self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " "which will be certainly limited and still need to configure all over again.", " ", " " ], " For all other languages you still need to find out another source code f\n" - " tool, which will be certainly limited and still need to configure all over\n" - " again." ) + " tool,\n" + " which will be certainly limited and still need to configure all over again." ) def semantic_line_wrap(self, initial_text, goal): From 4b29968722af406ff01959b947d36dfbde5e0777 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 7 Nov 2017 19:14:11 -0200 Subject: [PATCH 021/160] Removed redundant debug variables and created a unit text only with numbers. --- wrap_plus.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 62e981e..ede98aa 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -717,10 +717,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): if comma_list_end_point > 0: comma_list_end_point -= 1 - comma_list_size = index - line_start_index - line_remaining_size = self._width - comma_list_size - - # print( "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, line_remaining_size, comma_list_end_point, character ) ) + # print( "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, index - line_start_index, self._width - index - line_start_index, comma_list_end_point, character ) ) if not is_flushing_accumalated_line: @@ -805,7 +802,7 @@ def peek_next_word_length(self, index, text): if match: next_word = match.group(0) - # print( "next_word: %s" % next_word ) + # print( "peek_next_word_length: %s" % next_word ) return len( next_word ) return 0 @@ -826,7 +823,8 @@ def is_comma_separated_list(self, text, index, line_start_index=0): # print( "is_comma_separated_list, character: %s, next_character: %s" % ( character, next_character ) ) - if character in word_separator_characters and next_character in whitespace_character \ + if ( character in word_separator_characters \ + and next_character in whitespace_character ) \ or index >= text_length: comma_section = text[ slice_start_index+1:index+1 ] @@ -847,12 +845,10 @@ def is_comma_separated_list(self, text, index, line_start_index=0): # `line_start_index` always greater than `index`, like 50 - 20 = 30 # 50, 20 = 30, 80 - 30 = 50, 50 - 10 = 40 - line_remaining_size = self._width - ( index - line_start_index ) - match_end - - # print( "is_comma_separated_list, line_remaining_size: " + str( line_remaining_size ) ) + # print( "is_comma_separated_list, line_remaining_size: " + str( self._width - ( index - line_start_index ) - match_end ) ) # print( "is_comma_separated_list, match_end: " + str( match_end ) ) - is_there_new_commas, possible_match_end = self.is_comma_separated_list(text, index, line_start_index + match_end) + is_there_new_commas, possible_match_end = self.is_comma_separated_list( text, index, line_start_index + match_end ) # print( "is_comma_separated_list, possible_match_end: " + str( possible_match_end ) ) if possible_match_end > 0: @@ -926,8 +922,8 @@ def print_text_replacements(self, text, selection): def plugin_loaded(): pass - print( "\n\n" ) - main() + # print( "\n\n" ) + # main() # wrap_plus = WrapLinesPlusCommand( None ) # wrap_plus._width = 80 @@ -1024,6 +1020,10 @@ def test_semantic_line_wrap_with_comma_list_on_the_end(self): self.semantic_line_wrap( "few languages close related. On this case, C, C++, Java, Pawn, etc. more over break this line", "few languages close related.\nOn this case, C, C++, Java, Pawn, etc.\nmore over break this line" ) + def test_semantic_line_wrap_with_numeric_comma_list_on_the_end(self): + self.semantic_line_wrap( "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1", + "1 2 3 4.\n5 6 7, 1, 2, 3, 4, 5.\n6 7 8 9 1" ) + def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): self.semantic_line_wrap( "For all other languages you still need to find out another source code " "formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/" From 830c411de6ef57aedbabae725cb9741daa1b45de Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 7 Nov 2017 19:38:57 -0200 Subject: [PATCH 022/160] Created the settingWrap Plus.semantic_line_wrap, if true, the semantic linewrap also know as semantic linefeed will be used. --- Base File.sublime-settings | 8 ++++++-- README.md | 5 +++++ wrap_plus.py | 20 +++++++++++++++----- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 50397bc..e182217 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -1,10 +1,14 @@ { // If true, words longer than the wrap width will be split to ensure lines // are not longer than the wrap width. - "WrapPlus.break_long_words": false, + "WrapPlus.break_long_words": false, // If true, will break on hyphens in compound words. - "WrapPlus.break_on_hyphens": false, + "WrapPlus.break_on_hyphens": false, + + // If true, the semantic linewrap also know as semantic linefeed will be used. See the following + // address for more descriptions: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ + "WrapPlus.semantic_line_wrap": false, // Determines whether or not line endings are included in the line size: // - true: Always included. diff --git a/README.md b/README.md index 91d4bb5..ad837a7 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,11 @@ There are a few settings you can tweak if you so desire. You can set them in ** true A single word that is longer than your wrap column will be forced to be break at the wrap column. + + "WrapPlus.semantic_line_wrap" + false + If true, the semantic linewrap also know as semantic linefeed will be used. See the following address for more descriptions: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ + "WrapPlus.break_on_hyphens" true diff --git a/wrap_plus.py b/wrap_plus.py index ede98aa..863a281 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -651,10 +651,21 @@ def run(self, edit, width=0): debug('examine %r', s) paragraphs.extend(self._find_paragraphs(s)) + view_settings = self.view.settings() debug('paragraphs is %r', paragraphs) - break_long_words = self.view.settings().get('WrapPlus.break_long_words', True) - break_on_hyphens = self.view.settings().get('WrapPlus.break_on_hyphens', True) + break_long_words = view_settings.get('WrapPlus.break_long_words', True) + break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) + + if view_settings.get('WrapPlus.semantic_line_wrap', False): + + def line_wrapper_type(): + return self.semantic_line_wrap(paragraph_lines, init_prefix, subsequent_prefix) + + else: + + def line_wrapper_type(): + return self.classic_wrap_text(wrapper, paragraph_lines, init_prefix, subsequent_prefix) wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) @@ -673,8 +684,7 @@ def run(self, edit, width=0): paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] init_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_region, paragraph_lines, required_comment_prefix) - # text = self.hard_wrap_text(wrapper, paragraph_lines, init_prefix, subsequent_prefix) - text = self.semantic_line_wrap(paragraph_lines, init_prefix, subsequent_prefix) + text = line_wrapper_type() # I can't decide if I prefer it to not make the modification # if there is no change (and thus don't mark an unmodified @@ -862,7 +872,7 @@ def is_comma_separated_list(self, text, index, line_start_index=0): return False, 0 - def hard_wrap_text(self, wrapper, paragraph_lines, init_prefix, subsequent_prefix): + def classic_wrap_text(self, wrapper, paragraph_lines, init_prefix, subsequent_prefix): orig_init_prefix = init_prefix orig_subsequent_prefix = subsequent_prefix From 4443a30f28c24c017d8e210576b5ff75c9a5e8ae Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 Nov 2017 00:56:31 -0200 Subject: [PATCH 023/160] Created the setting WrapPlus.minminimum_line_size_percent on Base File.sublime-settings --- Base File.sublime-settings | 8 +++++++ wrap_plus.py | 43 +++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index e182217..6ded3b4 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -10,6 +10,14 @@ // address for more descriptions: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ "WrapPlus.semantic_line_wrap": false, + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + // The minimum of the percentage of the current maximum line width a line can have. + // For example, if you `wrap_width` is set to 100, and you set this to `0.2`, it + // means that the minimum acceptable line length is 20 characters. Therefore if + // some line has less than 20 characters, it will not be wrapped and will be + // continued by the next sentence without wrapping. + "WrapPlus.minminimum_line_size_percent": 0.2, + // Determines whether or not line endings are included in the line size: // - true: Always included. // - false: Never included. diff --git a/wrap_plus.py b/wrap_plus.py index 863a281..f33db36 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -468,14 +468,14 @@ def _determine_width(self, width): :returns: The maximum line width. """ - # print( "Here1, width: " + str( width ) ) + # print( "_determine_width, width: " + str( width ) ) if width == 0 and self.view.settings().get('wrap_width'): try: width = int(self.view.settings().get('wrap_width')) except TypeError: pass - # print( "Here1, width: " + str( width ) ) + # print( "_determine_width, before get('rulers'), width: " + str( width ) ) if width == 0 and self.view.settings().get('rulers'): # try and guess the wrap width from the ruler, if any try: @@ -485,7 +485,7 @@ def _determine_width(self, width): except TypeError: pass - # print( "Here1, width: " + str( width ) ) + # print( "_determine_width, before get('WrapPlus.wrap_width', width): " + str( width ) ) if width == 0: width = self.view.settings().get('WrapPlus.wrap_width', width) @@ -654,13 +654,14 @@ def run(self, edit, width=0): view_settings = self.view.settings() debug('paragraphs is %r', paragraphs) - break_long_words = view_settings.get('WrapPlus.break_long_words', True) - break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) + break_long_words = view_settings.get('WrapPlus.break_long_words', True) + break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) + minimum_line_size_percent = view_settings.get('WrapPlus.minimum_line_size_percent', 0.2) if view_settings.get('WrapPlus.semantic_line_wrap', False): def line_wrapper_type(): - return self.semantic_line_wrap(paragraph_lines, init_prefix, subsequent_prefix) + return self.semantic_line_wrap(paragraph_lines, init_prefix, subsequent_prefix, minimum_line_size_percent) else: @@ -672,6 +673,8 @@ def line_wrapper_type(): wrapper.width = self._width wrapper.expand_tabs = False + # print( "self._width: " + str( self._width ) ) + if paragraphs: # Use view selections to handle shifts from the replace() command. self.view.sel().clear() @@ -695,25 +698,28 @@ def line_wrapper_type(): self.move_cursor_below_the_last_paragraph() - def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): + def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, minimum_line_size_percent=0.0): new_text = [init_prefix] init_prefix_length = len( init_prefix ) - is_possible_space = False - is_flushing_comma_list = False - is_comma_separated_list = False + is_allowed_to_wrap = False + is_possible_space = False + is_flushing_comma_list = False + is_comma_separated_list = False is_flushing_accumalated_line = False text = ' '.join(paragraph_lines) text_length = len(text) + minimum_line_size = int( self._width * minimum_line_size_percent ) + accumulated_line = "" line_start_index = 0 comma_list_end_point = 0 for index, character in enumerate(text): accumulated_line_length = len( accumulated_line ) - next_word_length = self.peek_next_word_length( index, text ) + next_word_length = self.peek_next_word_length( index, text ) if is_possible_space and character in whitespace_character: continue @@ -725,7 +731,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): # the `comma_list_end_point` is lower than the `self._width`, otherwise the line will # be immediately flushed if comma_list_end_point > 0: - comma_list_end_point -= 1 + comma_list_end_point -= 1 # print( "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, index - line_start_index, self._width - index - line_start_index, comma_list_end_point, character ) ) @@ -759,7 +765,10 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): # print( "semantic_line_wrap, character: %s " % ( character ) ) - if character in word_separator_characters \ + if accumulated_line_length > minimum_line_size: + is_allowed_to_wrap = True + + if character in word_separator_characters and is_allowed_to_wrap \ or is_flushing_accumalated_line: if index + 2 < text_length: @@ -788,7 +797,8 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix): accumulated_line = "" line_start_index = index + 1 - is_possible_space = True + is_possible_space = True + is_allowed_to_wrap = False is_flushing_accumalated_line = False else: @@ -979,7 +989,7 @@ def suite(): class WrapPlusUnitTests(unittest.TestCase): @classmethod - def setUpClass(self): + def setUp(self): self.maxDiff = None self.wrap_plus = WrapLinesPlusCommand( None ) self.wrap_plus._width = 80 @@ -1055,14 +1065,13 @@ def test_semantic_line_wrap_with_81_characters(self): self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprogram, assure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) - def test_semantic_line_wrap_with_81_characters_on_list_flusing(self): + def test_semantic_line_wrap_with_81_characters_on_list_flushing(self): self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprograms, assure, everything, is, under, versioning, control, system, and,\nbroke, everything, etc.\nmore over break this line" ) def test_semantic_line_wrap_with_initial_indentation(self): self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " "which will be certainly limited and still need to configure all over again.", " ", " " ], - " For all other languages you still need to find out another source code f\n" " tool,\n" " which will be certainly limited and still need to configure all over again." ) From cc3055dc2e20d358e8d1d1813107f236e1dab3cb Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 Nov 2017 01:27:57 -0200 Subject: [PATCH 024/160] Created the setting disable_line_wrapping_by_maximum_width to detects the maximum line width and uses it to limite/delimite the maximum line width. If you line your lines only to be wrapped by delimiter characters, you can set this to true. --- Base File.sublime-settings | 22 +++++++++++++++++----- wrap_plus.py | 27 +++++++++++++++++---------- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 6ded3b4..e311174 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -6,17 +6,29 @@ // If true, will break on hyphens in compound words. "WrapPlus.break_on_hyphens": false, - // If true, the semantic linewrap also know as semantic linefeed will be used. See the following - // address for more descriptions: http://rhodesmill.org/brandon/2012/one-sentence-per-line/ + // If true, the semantic linewrap also know as semantic linefeed will be used. + // See the following address for more descriptions: + // http://rhodesmill.org/brandon/2012/one-sentence-per-line/ "WrapPlus.semantic_line_wrap": false, - // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. // The minimum of the percentage of the current maximum line width a line can have. // For example, if you `wrap_width` is set to 100, and you set this to `0.2`, it // means that the minimum acceptable line length is 20 characters. Therefore if // some line has less than 20 characters, it will not be wrapped and will be // continued by the next sentence without wrapping. - "WrapPlus.minminimum_line_size_percent": 0.2, + // + // You can set this to 0 to disable the minimum width and always wrap the lines + // despite their size. + // + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + "WrapPlus.minimum_line_size_percent": 0.2, + + // The `semantic_line_wrap` detects the maximum line width and uses it to + // limite/delimite the maximum line width. If you line your lines only to be + // wrapped by delimiter characters, you can set this to true. + // + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + "WrapPlus.disable_line_wrapping_by_maximum_width": false, // Determines whether or not line endings are included in the line size: // - true: Always included. @@ -27,5 +39,5 @@ "WrapPlus.include_line_endings": "auto" // Set the wrap column, overriding Sublime's "wrap_width" if not 0. - //"WrapPlus.wrap_width": 78 + // "WrapPlus.wrap_width": 78 } diff --git a/wrap_plus.py b/wrap_plus.py index f33db36..38074bc 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -654,14 +654,18 @@ def run(self, edit, width=0): view_settings = self.view.settings() debug('paragraphs is %r', paragraphs) - break_long_words = view_settings.get('WrapPlus.break_long_words', True) - break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) - minimum_line_size_percent = view_settings.get('WrapPlus.minimum_line_size_percent', 0.2) + break_long_words = view_settings.get('WrapPlus.break_long_words', True) + break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) + minimum_line_size_percent = view_settings.get('WrapPlus.minimum_line_size_percent', 0.2) + disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.disable_line_wrapping_by_maximum_width', False) + + # print( "minimum_line_size_percent: " + str( minimum_line_size_percent ) ) if view_settings.get('WrapPlus.semantic_line_wrap', False): def line_wrapper_type(): - return self.semantic_line_wrap(paragraph_lines, init_prefix, subsequent_prefix, minimum_line_size_percent) + return self.semantic_line_wrap(paragraph_lines, init_prefix, subsequent_prefix, + minimum_line_size_percent, disable_line_wrapping_by_maximum_width) else: @@ -698,7 +702,8 @@ def line_wrapper_type(): self.move_cursor_below_the_last_paragraph() - def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, minimum_line_size_percent=0.0): + def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, + minimum_line_size_percent=0.0, disable_line_wrapping_by_maximum_width=False): new_text = [init_prefix] init_prefix_length = len( init_prefix ) @@ -712,6 +717,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, mi text_length = len(text) minimum_line_size = int( self._width * minimum_line_size_percent ) + # print( "minimum_line_size: %s" % ( minimum_line_size ) ) accumulated_line = "" line_start_index = 0 @@ -737,7 +743,9 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, mi if not is_flushing_accumalated_line: - if accumulated_line_length + next_word_length + init_prefix_length > self._width: + if not disable_line_wrapping_by_maximum_width \ + and accumulated_line_length + next_word_length + init_prefix_length > self._width: + # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_flushing_accumalated_line = True @@ -754,7 +762,9 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, mi is_flushing_comma_list = False is_comma_separated_list = False - if not is_flushing_accumalated_line \ + # print( "semantic_line_wrap, character: %s " % ( character ) ) + if not disable_line_wrapping_by_maximum_width \ + and not is_flushing_accumalated_line \ and accumulated_line_length + next_word_length + init_prefix_length > self._width: # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) @@ -763,8 +773,6 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, mi # Current character is a whitespace, but it must the the next, so fix the index index -= 1 - # print( "semantic_line_wrap, character: %s " % ( character ) ) - if accumulated_line_length > minimum_line_size: is_allowed_to_wrap = True @@ -842,7 +850,6 @@ def is_comma_separated_list(self, text, index, line_start_index=0): next_character = text[index+1] # print( "is_comma_separated_list, character: %s, next_character: %s" % ( character, next_character ) ) - if ( character in word_separator_characters \ and next_character in whitespace_character ) \ or index >= text_length: From 8a6e77e4c5c22137ca916f6a0d883c4129e96c5d Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 Nov 2017 18:07:15 -0200 Subject: [PATCH 025/160] Implemented the new setting balance_characters_between_line_wraps to balance the text between lines equally when a line wrapped due reaching the maximum wrap width. --- Base File.sublime-settings | 19 +++- wrap_plus.py | 187 +++++++++++++++++++++++++++++-------- 2 files changed, 165 insertions(+), 41 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index e311174..d921908 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -11,6 +11,20 @@ // http://rhodesmill.org/brandon/2012/one-sentence-per-line/ "WrapPlus.semantic_line_wrap": false, + // Balance the text between lines equally when a line wrapped due reaching the + // maximum wrap width. For example, if the maximum is 49 characters, the line: + // + // This is my very long line which will wrap near its + // end, + // + // Will become something like: + // + // This is my very long line which + // will wrap near its end, + // + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + "WrapPlus.balance_characters_between_line_wraps": true, + // The minimum of the percentage of the current maximum line width a line can have. // For example, if you `wrap_width` is set to 100, and you set this to `0.2`, it // means that the minimum acceptable line length is 20 characters. Therefore if @@ -21,13 +35,16 @@ // despite their size. // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + // If the setting `WrapPlus.balance_characters_between_line_wraps` is enabled, + // the this will be ignored. "WrapPlus.minimum_line_size_percent": 0.2, // The `semantic_line_wrap` detects the maximum line width and uses it to // limite/delimite the maximum line width. If you line your lines only to be // wrapped by delimiter characters, you can set this to true. // - // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled, + // and when `WrapPlus.balance_characters_between_line_wraps` is disabled. "WrapPlus.disable_line_wrapping_by_maximum_width": false, // Determines whether or not line endings are included in the line size: diff --git a/wrap_plus.py b/wrap_plus.py index 38074bc..27b2ffe 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -2,6 +2,7 @@ import sublime, sublime_plugin import textwrap import re +import math import time import unittest try: @@ -658,27 +659,37 @@ def run(self, edit, width=0): break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) minimum_line_size_percent = view_settings.get('WrapPlus.minimum_line_size_percent', 0.2) + balance_characters_between_line_wraps = view_settings.get('WrapPlus.balance_characters_between_line_wraps', False) disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.disable_line_wrapping_by_maximum_width', False) + wrapper = textwrap.TextWrapper(break_long_words=break_long_words, + break_on_hyphens=break_on_hyphens) + wrapper.width = self._width + wrapper.expand_tabs = False + # print( "minimum_line_size_percent: " + str( minimum_line_size_percent ) ) - if view_settings.get('WrapPlus.semantic_line_wrap', False): + if view_settings.get( 'WrapPlus.semantic_line_wrap', False ): def line_wrapper_type(): - return self.semantic_line_wrap(paragraph_lines, init_prefix, subsequent_prefix, - minimum_line_size_percent, disable_line_wrapping_by_maximum_width) + if balance_characters_between_line_wraps: + minimum_line_size_percent = 0.0 + disable_line_wrapping_by_maximum_width = True + + text = self.semantic_line_wrap( paragraph_lines, initial_prefix, subsequent_prefix, + minimum_line_size_percent, disable_line_wrapping_by_maximum_width ) + + if balance_characters_between_line_wraps: + wrapper.subsequent_indent = subsequent_prefix + text = self.balance_characters_between_line_wraps( wrapper, text ) + + return "".join( text ) else: def line_wrapper_type(): - return self.classic_wrap_text(wrapper, paragraph_lines, init_prefix, subsequent_prefix) - - wrapper = textwrap.TextWrapper(break_long_words=break_long_words, - break_on_hyphens=break_on_hyphens) - wrapper.width = self._width - wrapper.expand_tabs = False + return self.classic_wrap_text(wrapper, paragraph_lines, initial_prefix, subsequent_prefix) # print( "self._width: " + str( self._width ) ) - if paragraphs: # Use view selections to handle shifts from the replace() command. self.view.sel().clear() @@ -689,7 +700,7 @@ def line_wrapper_type(): # the calls to replace(). for index, selection in enumerate(self.view.sel()): paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] - init_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_region, paragraph_lines, required_comment_prefix) + initial_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_region, paragraph_lines, required_comment_prefix) text = line_wrapper_type() @@ -702,10 +713,72 @@ def line_wrapper_type(): self.move_cursor_below_the_last_paragraph() - def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, + def balance_characters_between_line_wraps(self, wrapper, text_lines): + new_text = [] + new_lines = self._split_lines( wrapper, text_lines, self._width ) + + for index, new_line in enumerate( new_lines ): + lines = new_line.split("\n") + lines_count = len( lines ) + lines_new_count = lines_count + + # When there are more than 2 lines, we can get a situation like this: + # lines: [' This is my very long line\n which will wrap near its\n end,'] + if lines_count > 2: + lengths = [ len( line ) for line in lines ] + + if lengths[-1] < lengths[-2] / 2: + increment_percent = 1.1 + + # safe guard to not attempt to fix it indefinitely, try until it reaches the maximum width + steps_taken = math.ceil( 2 / math.log( increment_percent, 2 ) ) + + # Try to increase the maximum width until the trailing line vanishes + while lines_count == lines_new_count \ + and steps_taken > 0: + + steps_taken -= 1 + lines = self._split_lines( wrapper, [text_lines[index]], self._width, increment_percent )[0].split("\n") + + lines_new_count = len( lines ) + increment_percent += increment_percent * 1.1 + + new_text.extend( lines ) + + # print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) + return new_text + + def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_line_increment_percent=1): + """ + (input) text_lines: [' This is my very long line which will wrap near its end,'] + (output) new_lines: [' This is my very long line\n which will wrap near its\n end,\n'] + """ + new_lines = [] + + for line in text_lines: + line_length = len( line ) + lines_count = math.ceil( line_length / maximum_line_width ) + 1 + + for step in range( 1, lines_count ): + line_length = math.ceil( line_length / step ) + + if line_length > maximum_line_width: + continue + + else: + break + + # print( "line_length: %d, lines_count: %d, maximum_line_width: %d, new_width: %d (%f)" % ( line_length, lines_count, maximum_line_width, math.ceil( line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) + wrapper.width = math.ceil( line_length * middle_of_the_line_increment_percent ) + new_lines.append( wrapper.fill( line ) ) + + print( "_split_lines, new_lines: " + str( new_lines ) ) + return new_lines + + def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, minimum_line_size_percent=0.0, disable_line_wrapping_by_maximum_width=False): - new_text = [init_prefix] - init_prefix_length = len( init_prefix ) + new_text = [initial_prefix] + initial_prefix_length = len( initial_prefix ) is_allowed_to_wrap = False is_possible_space = False @@ -723,7 +796,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, line_start_index = 0 comma_list_end_point = 0 - for index, character in enumerate(text): + for index, character in enumerate( text ): accumulated_line_length = len( accumulated_line ) next_word_length = self.peek_next_word_length( index, text ) @@ -744,7 +817,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, if not is_flushing_accumalated_line: if not disable_line_wrapping_by_maximum_width \ - and accumulated_line_length + next_word_length + init_prefix_length > self._width: + and accumulated_line_length + next_word_length + initial_prefix_length > self._width: # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_flushing_accumalated_line = True @@ -765,7 +838,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, # print( "semantic_line_wrap, character: %s " % ( character ) ) if not disable_line_wrapping_by_maximum_width \ and not is_flushing_accumalated_line \ - and accumulated_line_length + next_word_length + init_prefix_length > self._width: + and accumulated_line_length + next_word_length + initial_prefix_length > self._width: # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_flushing_accumalated_line = True @@ -796,7 +869,7 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, or is_flushing_accumalated_line: # It is not the first line anymore, now we need to care about the `subsequent_prefix` length - init_prefix_length = len( subsequent_prefix ) + initial_prefix_length = len( subsequent_prefix ) if character in whitespace_character: character = "" @@ -821,8 +894,8 @@ def semantic_line_wrap(self, paragraph_lines, init_prefix, subsequent_prefix, if len( accumulated_line ): new_text.append(accumulated_line) - # print( "semantic_line_wrap, new_text: " + str( new_text ) ) - return "".join(new_text) + print( "semantic_line_wrap, new_text: " + str( new_text ) ) + return new_text def peek_next_word_length(self, index, text): match = next_word_pattern.match( text, index ) @@ -889,18 +962,18 @@ def is_comma_separated_list(self, text, index, line_start_index=0): return False, 0 - def classic_wrap_text(self, wrapper, paragraph_lines, init_prefix, subsequent_prefix): - orig_init_prefix = init_prefix + def classic_wrap_text(self, wrapper, paragraph_lines, initial_prefix, subsequent_prefix): + orig_initial_prefix = initial_prefix orig_subsequent_prefix = subsequent_prefix - if orig_init_prefix or orig_subsequent_prefix: + if orig_initial_prefix or orig_subsequent_prefix: # Textwrap is somewhat limited. It doesn't recognize tabs # in prefixes. Unfortunately, this means we can't easily # differentiate between the initial and subsequent. This # is a workaround. - init_prefix = orig_init_prefix.expandtabs(self._tab_width) + initial_prefix = orig_initial_prefix.expandtabs(self._tab_width) subsequent_prefix = orig_subsequent_prefix.expandtabs(self._tab_width) - wrapper.initial_indent = init_prefix + wrapper.initial_indent = initial_prefix wrapper.subsequent_indent = subsequent_prefix text = '\n'.join(paragraph_lines) @@ -908,14 +981,14 @@ def classic_wrap_text(self, wrapper, paragraph_lines, init_prefix, subsequent_pr text = wrapper.fill(text) # Put the tabs back to the prefixes. - if orig_init_prefix or orig_subsequent_prefix: + if orig_initial_prefix or orig_subsequent_prefix: - if init_prefix != orig_subsequent_prefix or subsequent_prefix != orig_subsequent_prefix: + if initial_prefix != orig_subsequent_prefix or subsequent_prefix != orig_subsequent_prefix: lines = text.splitlines() - if init_prefix != orig_init_prefix: + if initial_prefix != orig_initial_prefix: debug('fix tabs %r', lines[0]) - lines[0] = orig_init_prefix + lines[0][len(init_prefix):] + lines[0] = orig_initial_prefix + lines[0][len(initial_prefix):] debug('new line is %r', lines[0]) if subsequent_prefix != orig_subsequent_prefix: @@ -949,11 +1022,12 @@ def print_text_replacements(self, text, selection): def plugin_loaded(): pass - # print( "\n\n" ) - # main() + print( "\n\n" ) + # run_unit_tests() + + wrap_plus = WrapLinesPlusCommand( None ) + wrap_plus._width = 80 - # wrap_plus = WrapLinesPlusCommand( None ) - # wrap_plus._width = 80 # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) # wrap_plus.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "which will not more take, you quite oh the time, some time, more time, the time, per time" ], "", "" ) @@ -962,12 +1036,20 @@ def plugin_loaded(): # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, which" ], " ", " " ) + wrapper = textwrap.TextWrapper(break_long_words=False, break_on_hyphens=False) + wrap_plus = WrapLinesPlusCommand( None ) + wrap_plus._width = 50 + wrapper.expand_tabs = False + wrapper.subsequent_indent = " " -def main(): + # wrap_plus._split_lines( wrapper, [" This is my very long line which will wrap near its end,"], 50 ) + wrap_plus.balance_characters_between_line_wraps( wrapper, [" This is my very long line which will wrap near its end,"]) + + +def run_unit_tests(): runner = unittest.TextTestRunner() runner.run( suite() ) - def suite(): """ Problem with sys.argv[1] when unittest module is in a script @@ -980,7 +1062,11 @@ def suite(): https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python """ suite = unittest.TestSuite() - classes = [ WrapPlusUnitTests ] + classes = \ + [ + SemanticLineWrapUnitTests, + LineBalancingUnitTests, + ] for _class in classes: _object = _class() @@ -988,12 +1074,33 @@ def suite(): for methode_name in dir( _object ): if methode_name.lower().startswith( "test" ): - suite.addTest( WrapPlusUnitTests( methode_name ) ) + suite.addTest( _class( methode_name ) ) return suite -class WrapPlusUnitTests(unittest.TestCase): +class LineBalancingUnitTests(unittest.TestCase): + + @classmethod + def setUp(self): + self.maxDiff = None + self.wrap_plus = WrapLinesPlusCommand( None ) + self.wrap_plus._width = 50 + + self.wrapper = textwrap.TextWrapper(break_long_words=False, break_on_hyphens=False) + self.wrapper.subsequent_indent = " " + self.wrapper.expand_tabs = False + + def test_split_lines(self): + self.assertEqual( [' This is my very long line\n which will wrap near its\n end,'], + self.wrap_plus._split_lines( self.wrapper, [" This is my very long line which will wrap near its end,"], 50 ) ) + + def test_balance_characters_between_line_wraps(self): + self.assertEqual( [' This is my very long line', ' which will wrap near its end,'], + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, [" This is my very long line which will wrap near its end,"] ) ) + +class SemanticLineWrapUnitTests(unittest.TestCase): @classmethod def setUp(self): @@ -1086,9 +1193,9 @@ def test_semantic_line_wrap_with_initial_indentation(self): def semantic_line_wrap(self, initial_text, goal): if isinstance( initial_text, list ): - self.assertEqual( goal, self.wrap_plus.semantic_line_wrap( [initial_text[0]], initial_text[1], initial_text[2] ) ) + self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text[0]], initial_text[1], initial_text[2] ) ) ) else: - self.assertEqual( goal, self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) + self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) ) From 7e5de35f8438ee40293074377923661bc57df05b Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 Nov 2017 21:57:15 -0200 Subject: [PATCH 026/160] Created the first 4 unit tests for the LineBalancingUnitTests class --- wrap_plus.py | 207 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 139 insertions(+), 68 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 27b2ffe..968f59b 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -676,11 +676,11 @@ def line_wrapper_type(): disable_line_wrapping_by_maximum_width = True text = self.semantic_line_wrap( paragraph_lines, initial_prefix, subsequent_prefix, - minimum_line_size_percent, disable_line_wrapping_by_maximum_width ) + minimum_line_size_percent, disable_line_wrapping_by_maximum_width, + balance_characters_between_line_wraps ) if balance_characters_between_line_wraps: - wrapper.subsequent_indent = subsequent_prefix - text = self.balance_characters_between_line_wraps( wrapper, text ) + text = self.balance_characters_between_line_wraps( wrapper, text, initial_prefix, subsequent_prefix ) return "".join( text ) @@ -713,45 +713,49 @@ def line_wrapper_type(): self.move_cursor_below_the_last_paragraph() - def balance_characters_between_line_wraps(self, wrapper, text_lines): - new_text = [] - new_lines = self._split_lines( wrapper, text_lines, self._width ) + def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_prefix, subsequent_prefix): + """ + input: ['This is my very long line which will wrap near its end,'] + output: [' ', 'This is my very long line which\n ', 'will wrap near its end,'] + """ + wrapper.initial_prefix = "" + wrapper.subsequent_indent = subsequent_prefix + + new_text = [initial_prefix] + splited_lines = self._split_lines( wrapper, text_lines, self._width, subsequent_prefix ) - for index, new_line in enumerate( new_lines ): - lines = new_line.split("\n") - lines_count = len( lines ) - lines_new_count = lines_count + for index, new_lines in enumerate( splited_lines ): + lines_count = len( new_lines ) + first_lines_count = lines_count # When there are more than 2 lines, we can get a situation like this: - # lines: [' This is my very long line\n which will wrap near its\n end,'] + # new_lines: [' This is my very long line\n which will wrap near its\n end,'] if lines_count > 2: - lengths = [ len( line ) for line in lines ] - if lengths[-1] < lengths[-2] / 2: + if len( new_lines[-1] ) < math.ceil( len( new_lines[-2] ) / 2 ): increment_percent = 1.1 - # safe guard to not attempt to fix it indefinitely, try until it reaches the maximum width - steps_taken = math.ceil( 2 / math.log( increment_percent, 2 ) ) - # Try to increase the maximum width until the trailing line vanishes - while lines_count == lines_new_count \ - and steps_taken > 0: + while lines_count == first_lines_count \ + and increment_percent < 2: + + new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, subsequent_prefix, increment_percent )[0] - steps_taken -= 1 - lines = self._split_lines( wrapper, [text_lines[index]], self._width, increment_percent )[0].split("\n") + first_lines_count = len( new_lines ) + increment_percent *= 1.1 - lines_new_count = len( lines ) - increment_percent += increment_percent * 1.1 + new_text.extend( new_lines ) - new_text.extend( lines ) + # The first line need to be manually fixed by removing the fist indentation + new_text[1] = new_text[1].lstrip() - # print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) + print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) return new_text - def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_line_increment_percent=1): + def _split_lines(self, wrapper, text_lines, maximum_line_width, subsequent_prefix, middle_of_the_line_increment_percent=1): """ - (input) text_lines: [' This is my very long line which will wrap near its end,'] - (output) new_lines: [' This is my very long line\n which will wrap near its\n end,\n'] + (input) text_lines: ['This is my very long line which will wrap near its end,\n'] + (output) new_lines: [[' This is my very long line\n', ' which will wrap near its\n', ' end,\n']] """ new_lines = [] @@ -770,15 +774,43 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li # print( "line_length: %d, lines_count: %d, maximum_line_width: %d, new_width: %d (%f)" % ( line_length, lines_count, maximum_line_width, math.ceil( line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) wrapper.width = math.ceil( line_length * middle_of_the_line_increment_percent ) - new_lines.append( wrapper.fill( line ) ) + wrapped_line = wrapper.fill( line ) + wrapped_lines = wrapped_line.split( "\n" ) + + # Add again the removed `\n` character due the `split` statement + fixed_wrapped_lines = [] + + for _wrapped_line in wrapped_lines: + fixed_wrapped_lines.append( _wrapped_line + "\n" ) + + # The first line need to be manually fixed by adding the fist indentation + fixed_wrapped_lines[0] = subsequent_prefix + fixed_wrapped_lines[0] + + # The last line need to be manually fixed by removing the trailing last time, if not existent on the original + if line[-1] != "\n": + fixed_wrapped_lines[-1] = fixed_wrapped_lines[-1][0:-1] + + new_lines.append( fixed_wrapped_lines ) print( "_split_lines, new_lines: " + str( new_lines ) ) return new_lines def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, - minimum_line_size_percent=0.0, disable_line_wrapping_by_maximum_width=False): - new_text = [initial_prefix] - initial_prefix_length = len( initial_prefix ) + minimum_line_size_percent=0.0, disable_line_wrapping_by_maximum_width=False, + balance_characters_between_line_wraps=False): + """ + input: ['This is my very long line which will wrap near its', 'end,'] + if balance_characters_between_line_wraps: + output: ['This is my very long line which will wrap near its end,'] + else: + output: [' ', 'This is my very long line which will wrap near its\n ', 'end,'] + """ + new_text = [] + initial_prefix_length = len( initial_prefix ) + subsequent_prefix_length = len( subsequent_prefix ) + + if not balance_characters_between_line_wraps: + new_text.append( initial_prefix ) is_allowed_to_wrap = False is_possible_space = False @@ -868,13 +900,18 @@ def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, or not is_comma_separated_list \ or is_flushing_accumalated_line: - # It is not the first line anymore, now we need to care about the `subsequent_prefix` length - initial_prefix_length = len( subsequent_prefix ) + # It is not the first line anymore, now we need to use the `subsequent_prefix_length` + initial_prefix_length = subsequent_prefix_length if character in whitespace_character: character = "" - new_text.append( accumulated_line + character + "\n" + subsequent_prefix ) + accumulated_line = "".join( [accumulated_line, character, "\n", + ( "" if balance_characters_between_line_wraps else subsequent_prefix ) ] ) + + # print( "semantic_line_wrap, accumulated_line flush: %s" % accumulated_line ) + new_text.append( accumulated_line ) + accumulated_line = "" line_start_index = index + 1 @@ -891,6 +928,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, else: accumulated_line += character + # Flush out any remaining text if len( accumulated_line ): new_text.append(accumulated_line) @@ -1022,12 +1060,13 @@ def print_text_replacements(self, text, selection): def plugin_loaded(): pass - print( "\n\n" ) + # print( "\n\n" ) # run_unit_tests() wrap_plus = WrapLinesPlusCommand( None ) wrap_plus._width = 80 + # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "", balance_characters_between_line_wraps=True ) # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) # wrap_plus.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "", "" ) # wrap_plus.semantic_line_wrap( [ "which will not more take, you quite oh the time, some time, more time, the time, per time" ], "", "" ) @@ -1042,41 +1081,24 @@ def plugin_loaded(): wrapper.expand_tabs = False wrapper.subsequent_indent = " " - # wrap_plus._split_lines( wrapper, [" This is my very long line which will wrap near its end,"], 50 ) - wrap_plus.balance_characters_between_line_wraps( wrapper, [" This is my very long line which will wrap near its end,"]) + # wrap_plus._split_lines( wrapper, ["This is my very long line which will wrap near its end,\n"], 50, " " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, ["This is my very long line which will wrap near its end,\n"], " ", " " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, ["This is my very long line which will wrap near its end,", "This is my very long line which will wrap near its end," ], " ", " " ) def run_unit_tests(): runner = unittest.TextTestRunner() - runner.run( suite() ) -def suite(): - """ - Problem with sys.argv[1] when unittest module is in a script - https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script - - Is there a way to loop through and execute all of the functions in a Python class? - https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute-all-of-the-functions - - looping over all member variables of a class in python - https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python - """ - suite = unittest.TestSuite() - classes = \ + # Comment all tests on this list to run all Unit Tests + unit_tests_to_run = \ [ - SemanticLineWrapUnitTests, - LineBalancingUnitTests, + # "test_split_lines_with_trailing_new_line", + # "test_split_lines_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_with_trailing_new_line", + # "test_balance_characters_between_line_wraps_without_trailing_new_line", ] - for _class in classes: - _object = _class() - - for methode_name in dir( _object ): - - if methode_name.lower().startswith( "test" ): - suite.addTest( _class( methode_name ) ) - - return suite + runner.run( suite( unit_tests_to_run ) ) class LineBalancingUnitTests(unittest.TestCase): @@ -1091,14 +1113,26 @@ def setUp(self): self.wrapper.subsequent_indent = " " self.wrapper.expand_tabs = False - def test_split_lines(self): - self.assertEqual( [' This is my very long line\n which will wrap near its\n end,'], - self.wrap_plus._split_lines( self.wrapper, [" This is my very long line which will wrap near its end,"], 50 ) ) + def test_split_lines_without_trailing_new_line(self): + self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,']], + self.wrap_plus._split_lines( + self.wrapper, ["This is my very long line which will wrap near its end,"], 50, " " ) ) + + def test_split_lines_with_trailing_new_line(self): + self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,\n']], + self.wrap_plus._split_lines( + self.wrapper, ["This is my very long line which will wrap near its end,\n"], 50, " " ) ) - def test_balance_characters_between_line_wraps(self): - self.assertEqual( [' This is my very long line', ' which will wrap near its end,'], + def test_balance_characters_between_line_wraps_with_trailing_new_line(self): + self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,\n'], self.wrap_plus.balance_characters_between_line_wraps( - self.wrapper, [" This is my very long line which will wrap near its end,"] ) ) + self.wrapper, ["This is my very long line which will wrap near its end,\n"], " ", " " ) ) + + def test_balance_characters_between_line_wraps_without_trailing_new_line(self): + self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,'], + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, ["This is my very long line which will wrap near its end,"], " ", " " ) ) + class SemanticLineWrapUnitTests(unittest.TestCase): @@ -1199,3 +1233,40 @@ def semantic_line_wrap(self, initial_text, goal): self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) ) +def suite(unit_tests_to_run): + """ + Problem with sys.argv[1] when unittest module is in a script + https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script + + Is there a way to loop through and execute all of the functions in a Python class? + https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute-all-of-the-functions + + looping over all member variables of a class in python + https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python + """ + suite = unittest.TestSuite() + classes = \ + [ + SemanticLineWrapUnitTests, + LineBalancingUnitTests, + ] + + unit_tests_to_run_count = len( unit_tests_to_run ) + + for _class in classes: + _object = _class() + + for function_name in dir( _object ): + + if function_name.lower().startswith( "test" ): + + if unit_tests_to_run_count > 0 \ + and function_name not in unit_tests_to_run: + + continue + + suite.addTest( _class( function_name ) ) + + return suite + + From 27db11f2b5f99b96cbb4ca2bcb16ebc286c00d56 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 Nov 2017 22:11:34 -0200 Subject: [PATCH 027/160] Deprecated the setting minimum_line_size_percent requiring the setting balance_characters_between_line_wraps to be disabled. --- Base File.sublime-settings | 22 ++++++++++------------ wrap_plus.py | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index d921908..03ee39e 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -25,26 +25,24 @@ // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. "WrapPlus.balance_characters_between_line_wraps": true, - // The minimum of the percentage of the current maximum line width a line can have. - // For example, if you `wrap_width` is set to 100, and you set this to `0.2`, it - // means that the minimum acceptable line length is 20 characters. Therefore if - // some line has less than 20 characters, it will not be wrapped and will be - // continued by the next sentence without wrapping. + // The minimum of the percentage of the current maximum line width a line can + // have. For example, if you `wrap_width` is set to 100, and you set this to `0.2`, + // it means that the minimum acceptable line length is 20 characters. // - // You can set this to 0 to disable the minimum width and always wrap the lines - // despite their size. + // Therefore if some line has less than 20 characters, it will not be wrapped and + // will be continued by the next sentence without wrapping. You can set this to 0 + // to disable the minimum width and always wrap the lines despite their size. // - // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. - // If the setting `WrapPlus.balance_characters_between_line_wraps` is enabled, - // the this will be ignored. + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled, "WrapPlus.minimum_line_size_percent": 0.2, // The `semantic_line_wrap` detects the maximum line width and uses it to // limite/delimite the maximum line width. If you line your lines only to be // wrapped by delimiter characters, you can set this to true. // - // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled, - // and when `WrapPlus.balance_characters_between_line_wraps` is disabled. + // * This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + // * If the setting `WrapPlus.balance_characters_between_line_wraps` is enabled, + // this setting will be ignored. "WrapPlus.disable_line_wrapping_by_maximum_width": false, // Determines whether or not line endings are included in the line size: diff --git a/wrap_plus.py b/wrap_plus.py index 968f59b..34804dc 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -672,7 +672,7 @@ def run(self, edit, width=0): def line_wrapper_type(): if balance_characters_between_line_wraps: - minimum_line_size_percent = 0.0 + # minimum_line_size_percent = 0.0 disable_line_wrapping_by_maximum_width = True text = self.semantic_line_wrap( paragraph_lines, initial_prefix, subsequent_prefix, From 14573cf4e93820bd2e62a722763d0a4eacbf1fa4 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 Nov 2017 23:01:07 -0200 Subject: [PATCH 028/160] Fixed long word not wrapping correctly the sentence when they occur on the end of the line. --- Base File.sublime-settings | 2 +- wrap_plus.py | 68 ++++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 03ee39e..e21c74b 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -34,7 +34,7 @@ // to disable the minimum width and always wrap the lines despite their size. // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled, - "WrapPlus.minimum_line_size_percent": 0.2, + "WrapPlus.minimum_line_size_percent": 0.0, // The `semantic_line_wrap` detects the maximum line width and uses it to // limite/delimite the maximum line width. If you line your lines only to be diff --git a/wrap_plus.py b/wrap_plus.py index 34804dc..d424de2 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -731,25 +731,36 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_pre # When there are more than 2 lines, we can get a situation like this: # new_lines: [' This is my very long line\n which will wrap near its\n end,'] if lines_count > 2: + new_lines_reversed = list( reversed( new_lines ) ) - if len( new_lines[-1] ) < math.ceil( len( new_lines[-2] ) / 2 ): - increment_percent = 1.1 + for _index, new_line in enumerate( new_lines_reversed ): + next_index = _index + 1 - # Try to increase the maximum width until the trailing line vanishes - while lines_count == first_lines_count \ - and increment_percent < 2: + if next_index < lines_count \ + and len( new_line ) < math.ceil( len( new_lines_reversed[next_index] ) / 2 ): - new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, subsequent_prefix, increment_percent )[0] + break - first_lines_count = len( new_lines ) - increment_percent *= 1.1 + else: + continue + + increment_percent = 1.1 + + # Try to increase the maximum width until the trailing line vanishes + while lines_count == first_lines_count \ + and increment_percent < 2: + + new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, subsequent_prefix, increment_percent )[0] + + first_lines_count = len( new_lines ) + increment_percent *= 1.1 new_text.extend( new_lines ) # The first line need to be manually fixed by removing the fist indentation new_text[1] = new_text[1].lstrip() - print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) + # print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) return new_text def _split_lines(self, wrapper, text_lines, maximum_line_width, subsequent_prefix, middle_of_the_line_increment_percent=1): @@ -764,16 +775,17 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, subsequent_prefi lines_count = math.ceil( line_length / maximum_line_width ) + 1 for step in range( 1, lines_count ): - line_length = math.ceil( line_length / step ) + new_line_length = math.ceil( line_length / step ) + # print( "new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) - if line_length > maximum_line_width: + if new_line_length > maximum_line_width: continue else: break - # print( "line_length: %d, lines_count: %d, maximum_line_width: %d, new_width: %d (%f)" % ( line_length, lines_count, maximum_line_width, math.ceil( line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) - wrapper.width = math.ceil( line_length * middle_of_the_line_increment_percent ) + # print( "maximum_line_width: %d, new_width: %d (%f)" % ( maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) + wrapper.width = math.ceil( new_line_length * middle_of_the_line_increment_percent ) wrapped_line = wrapper.fill( line ) wrapped_lines = wrapped_line.split( "\n" ) @@ -792,7 +804,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, subsequent_prefi new_lines.append( fixed_wrapped_lines ) - print( "_split_lines, new_lines: " + str( new_lines ) ) + # print( "_split_lines, new_lines: " + str( new_lines ) ) return new_lines def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, @@ -932,7 +944,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, if len( accumulated_line ): new_text.append(accumulated_line) - print( "semantic_line_wrap, new_text: " + str( new_text ) ) + # print( "semantic_line_wrap, new_text: " + str( new_text ) ) return new_text def peek_next_word_length(self, index, text): @@ -1081,9 +1093,15 @@ def plugin_loaded(): wrapper.expand_tabs = False wrapper.subsequent_indent = " " - # wrap_plus._split_lines( wrapper, ["This is my very long line which will wrap near its end,\n"], 50, " " ) - # wrap_plus.balance_characters_between_line_wraps( wrapper, ["This is my very long line which will wrap near its end,\n"], " ", " " ) - # wrap_plus.balance_characters_between_line_wraps( wrapper, ["This is my very long line which will wrap near its end,", "This is my very long line which will wrap near its end," ], " ", " " ) + # wrap_plus._split_lines( wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50, " " ) + # wrap_plus._split_lines( wrapper, [ "This is my very long line which will wrap near its end,\n" ], 50, " " ) + + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,\n" ], " ", " " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,", "This is my very long line which will wrap near its end," ], " ", " " ) + + wrap_plus._width = 80 + # wrap_plus._split_lines( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], 80, " " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], " ", " " ) def run_unit_tests(): @@ -1096,6 +1114,7 @@ def run_unit_tests(): # "test_split_lines_without_trailing_new_line", # "test_balance_characters_between_line_wraps_with_trailing_new_line", # "test_balance_characters_between_line_wraps_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_ending_with_long_word", ] runner.run( suite( unit_tests_to_run ) ) @@ -1123,6 +1142,11 @@ def test_split_lines_with_trailing_new_line(self): self.wrap_plus._split_lines( self.wrapper, ["This is my very long line which will wrap near its end,\n"], 50, " " ) ) + def test_split_lines_with_very_long_line_and_word(self): + self.assertEqual( [[' This is my very long line which my\n', ' very long line which\n', ' my_very_long_line_which_will_wrap_near_its_end,']], + self.wrap_plus._split_lines( + self.wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50, " " ) ) + def test_balance_characters_between_line_wraps_with_trailing_new_line(self): self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,\n'], self.wrap_plus.balance_characters_between_line_wraps( @@ -1133,6 +1157,14 @@ def test_balance_characters_between_line_wraps_without_trailing_new_line(self): self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, ["This is my very long line which will wrap near its end,"], " ", " " ) ) + def test_balance_characters_between_line_wraps_ending_with_long_word(self): + self.wrap_plus._width = 80 + self.assertEqual( [' ', 'In this proposal last chapter which lies on the part\n', + " called `\\nameref{sec:software_implementation}',"], + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, [ "In this proposal last chapter which lies on the part called " + "`\\nameref{sec:software_implementation}'," ], " ", " " ) ) + class SemanticLineWrapUnitTests(unittest.TestCase): From 69e054cc55cff802b5f8356767e8c090fec3ff78 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 Nov 2017 23:14:09 -0200 Subject: [PATCH 029/160] Created the setting maximum_words_in_comma_separated_list to control the number of words between sequential commas, to be considered a list of words. --- Base File.sublime-settings | 6 ++++++ wrap_plus.py | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index e21c74b..3c0dd6d 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -36,6 +36,12 @@ // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled, "WrapPlus.minimum_line_size_percent": 0.0, + // When wrapping lines, it will consider they to be a list of words if between + // two sequential commas is find at the maximum these number of words. + // + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled, + "WrapPlus.maximum_words_in_comma_separated_list": 3, + // The `semantic_line_wrap` detects the maximum line width and uses it to // limite/delimite the maximum line width. If you line your lines only to be // wrapped by delimiter characters, you can set this to true. diff --git a/wrap_plus.py b/wrap_plus.py index d424de2..d586432 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -213,7 +213,7 @@ def CONCAT(*args): return '(?:' + ''.join(args) + ')' blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') -max_words_in_comma_separated_list = 4 +maximum_words_in_comma_separated_list = 4 list_of_words_pattern = re.compile(r'(?:^|\s)+[^ ]+', re.MULTILINE) next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) @@ -640,14 +640,16 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): def run(self, edit, width=0): debug_start(self.view.settings().get('WrapPlus.debug', False)) debug('\n\n#########################################################################') - self._width = self._determine_width(width) + self._width = self._determine_width(width) # print('wrap width = %r', self._width) + self._determine_tab_size() self._determine_comment_style() # paragraphs is a list of (region, lines, comment_prefix) tuples. paragraphs = [] + for s in self.view.sel(): debug('examine %r', s) paragraphs.extend(self._find_paragraphs(s)) @@ -655,12 +657,14 @@ def run(self, edit, width=0): view_settings = self.view.settings() debug('paragraphs is %r', paragraphs) + global maximum_words_in_comma_separated_list break_long_words = view_settings.get('WrapPlus.break_long_words', True) break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) minimum_line_size_percent = view_settings.get('WrapPlus.minimum_line_size_percent', 0.2) balance_characters_between_line_wraps = view_settings.get('WrapPlus.balance_characters_between_line_wraps', False) disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.disable_line_wrapping_by_maximum_width', False) + maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.maximum_words_in_comma_separated_list', 3) + 1 wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) @@ -984,7 +988,7 @@ def is_comma_separated_list(self, text, index, line_start_index=0): results_count = len( results ) # print( "is_comma_separated_list, results: " + str( results ) ) - if 0 < results_count < max_words_in_comma_separated_list: + if 0 < results_count < maximum_words_in_comma_separated_list: # Get the last match object for match in list_of_words_pattern.finditer( comma_section ): @@ -1125,6 +1129,7 @@ class LineBalancingUnitTests(unittest.TestCase): @classmethod def setUp(self): self.maxDiff = None + self.wrap_plus = WrapLinesPlusCommand( None ) self.wrap_plus._width = 50 @@ -1132,6 +1137,9 @@ def setUp(self): self.wrapper.subsequent_indent = " " self.wrapper.expand_tabs = False + global maximum_words_in_comma_separated_list + maximum_words_in_comma_separated_list = 4 + def test_split_lines_without_trailing_new_line(self): self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,']], self.wrap_plus._split_lines( @@ -1174,6 +1182,9 @@ def setUp(self): self.wrap_plus = WrapLinesPlusCommand( None ) self.wrap_plus._width = 80 + global maximum_words_in_comma_separated_list + maximum_words_in_comma_separated_list = 4 + def test_is_command_separated_list(self): self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, True ) self.is_comma_separated_list( "1_ 2, 3, 4_ 5", 4, True ) From 99108f5e61a18c9acffa368a431a9cfc678ffdfd Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 00:10:00 -0200 Subject: [PATCH 030/160] Fixed misspellings on Base File.sublime-settings --- Base File.sublime-settings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 3c0dd6d..0e680c4 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -33,13 +33,13 @@ // will be continued by the next sentence without wrapping. You can set this to 0 // to disable the minimum width and always wrap the lines despite their size. // - // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled, + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. "WrapPlus.minimum_line_size_percent": 0.0, // When wrapping lines, it will consider they to be a list of words if between // two sequential commas is find at the maximum these number of words. // - // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled, + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. "WrapPlus.maximum_words_in_comma_separated_list": 3, // The `semantic_line_wrap` detects the maximum line width and uses it to From 7a216f3ca939f86dc6c38ee8e052c969cd08929e Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 00:16:20 -0200 Subject: [PATCH 031/160] Placed the manual tests into their own function. --- wrap_plus.py | 58 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index d586432..2695e4a 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1075,11 +1075,40 @@ def print_text_replacements(self, text, selection): def plugin_loaded(): + """ + Running single test from unittest.TestCase via command line + https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line + """ pass # print( "\n\n" ) # run_unit_tests() + # run_manual_tests() - wrap_plus = WrapLinesPlusCommand( None ) + +def run_unit_tests(): + runner = unittest.TextTestRunner() + + # Comment all the tests names on this list, to run all Unit Tests + unit_tests_to_run = \ + [ + # "test_split_lines_with_trailing_new_line", + # "test_split_lines_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_with_trailing_new_line", + # "test_balance_characters_between_line_wraps_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_ending_with_long_word", + ] + + classes = \ + [ + SemanticLineWrapUnitTests, + LineBalancingUnitTests, + ] + + runner.run( suite( classes, unit_tests_to_run ) ) + + +def run_manual_tests(): + wrap_plus = WrapLinesPlusCommand( None ) wrap_plus._width = 80 # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "", balance_characters_between_line_wraps=True ) @@ -1104,25 +1133,10 @@ def plugin_loaded(): # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,", "This is my very long line which will wrap near its end," ], " ", " " ) wrap_plus._width = 80 - # wrap_plus._split_lines( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], 80, " " ) + wrap_plus._split_lines( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], 80, " " ) # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], " ", " " ) -def run_unit_tests(): - runner = unittest.TextTestRunner() - - # Comment all tests on this list to run all Unit Tests - unit_tests_to_run = \ - [ - # "test_split_lines_with_trailing_new_line", - # "test_split_lines_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_with_trailing_new_line", - # "test_balance_characters_between_line_wraps_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_ending_with_long_word", - ] - - runner.run( suite( unit_tests_to_run ) ) - class LineBalancingUnitTests(unittest.TestCase): @@ -1276,7 +1290,7 @@ def semantic_line_wrap(self, initial_text, goal): self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) ) -def suite(unit_tests_to_run): +def suite(classes, unit_tests_to_run): """ Problem with sys.argv[1] when unittest module is in a script https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script @@ -1287,13 +1301,7 @@ def suite(unit_tests_to_run): looping over all member variables of a class in python https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python """ - suite = unittest.TestSuite() - classes = \ - [ - SemanticLineWrapUnitTests, - LineBalancingUnitTests, - ] - + suite = unittest.TestSuite() unit_tests_to_run_count = len( unit_tests_to_run ) for _class in classes: From 104b7f71cd73b79f272ce955c354e14001127408 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 00:40:17 -0200 Subject: [PATCH 032/160] Fixed misspelling word like on Base File.sublime-settings --- Base File.sublime-settings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 0e680c4..2f00655 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -43,7 +43,7 @@ "WrapPlus.maximum_words_in_comma_separated_list": 3, // The `semantic_line_wrap` detects the maximum line width and uses it to - // limite/delimite the maximum line width. If you line your lines only to be + // limite/delimite the maximum line width. If you like your lines only to be // wrapped by delimiter characters, you can set this to true. // // * This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. From 594a76d0992939607b4085ed10fb3042264d5a19 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 14:50:04 -0200 Subject: [PATCH 033/160] Moved the unit_tests_to_run array after the unit test classes array --- wrap_plus.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 2695e4a..6b3238e 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1088,6 +1088,12 @@ def plugin_loaded(): def run_unit_tests(): runner = unittest.TextTestRunner() + classes = \ + [ + SemanticLineWrapUnitTests, + LineBalancingUnitTests, + ] + # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ @@ -1098,12 +1104,6 @@ def run_unit_tests(): # "test_balance_characters_between_line_wraps_ending_with_long_word", ] - classes = \ - [ - SemanticLineWrapUnitTests, - LineBalancingUnitTests, - ] - runner.run( suite( classes, unit_tests_to_run ) ) From ebdc4fab694b76cee0b93b9279288112ed30ea4e Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 16:23:54 -0200 Subject: [PATCH 034/160] Moved the units tests to the module tests/__init__.py --- tests/__init__.py | 0 tests/semantic_linefeed_manual_tests.py | 41 ++++ tests/semantic_linefeed_unit_tests.py | 217 ++++++++++++++++++++ unittesting.json | 9 + wrap_plus.py | 258 ++---------------------- 5 files changed, 289 insertions(+), 236 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/semantic_linefeed_manual_tests.py create mode 100644 tests/semantic_linefeed_unit_tests.py create mode 100644 unittesting.json diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py new file mode 100644 index 0000000..9bda4cd --- /dev/null +++ b/tests/semantic_linefeed_manual_tests.py @@ -0,0 +1,41 @@ + + +import sys + +import textwrap +import unittest + + +wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] + + +def run_manual_tests(): + wrap_plus = wrap_plus_module.WrapLinesPlusCommand( None ) + wrap_plus._width = 80 + + # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "", balance_characters_between_line_wraps=True ) + # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "which will not more take, you quite oh the time, some time, more time, the time, per time" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "few languages closely related. On this case, C, C++, Java, Pawn, etc. more over break this line" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ], "", "" ) + # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, which" ], " ", " " ) + + wrapper = textwrap.TextWrapper(break_long_words=False, break_on_hyphens=False) + wrap_plus = wrap_plus_module.WrapLinesPlusCommand( None ) + wrap_plus._width = 50 + wrapper.expand_tabs = False + wrapper.subsequent_indent = " " + + # wrap_plus._split_lines( wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50, " " ) + # wrap_plus._split_lines( wrapper, [ "This is my very long line which will wrap near its end,\n" ], 50, " " ) + + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,\n" ], " ", " " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,", "This is my very long line which will wrap near its end," ], " ", " " ) + + wrap_plus._width = 80 + wrap_plus._split_lines( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], 80, " " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], " ", " " ) + + diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py new file mode 100644 index 0000000..007b5d0 --- /dev/null +++ b/tests/semantic_linefeed_unit_tests.py @@ -0,0 +1,217 @@ + + +import sys + +import textwrap +import unittest + + +wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] + + +def run_unit_tests(): + runner = unittest.TextTestRunner() + + classes = \ + [ + SemanticLineWrapUnitTests, + LineBalancingUnitTests, + ] + + # Comment all the tests names on this list, to run all Unit Tests + unit_tests_to_run = \ + [ + # "test_split_lines_with_trailing_new_line", + # "test_split_lines_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_with_trailing_new_line", + # "test_balance_characters_between_line_wraps_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_ending_with_long_word", + ] + + runner.run( suite( classes, unit_tests_to_run ) ) + + + +class LineBalancingUnitTests(unittest.TestCase): + + @classmethod + def setUp(self): + self.maxDiff = None + + self.wrap_plus = wrap_plus_module.WrapLinesPlusCommand( None ) + self.wrap_plus._width = 50 + + self.wrapper = textwrap.TextWrapper(break_long_words=False, break_on_hyphens=False) + self.wrapper.subsequent_indent = " " + self.wrapper.expand_tabs = False + + global maximum_words_in_comma_separated_list + maximum_words_in_comma_separated_list = 4 + + def test_split_lines_without_trailing_new_line(self): + self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,']], + self.wrap_plus._split_lines( + self.wrapper, ["This is my very long line which will wrap near its end,"], 50, " " ) ) + + def test_split_lines_with_trailing_new_line(self): + self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,\n']], + self.wrap_plus._split_lines( + self.wrapper, ["This is my very long line which will wrap near its end,\n"], 50, " " ) ) + + def test_split_lines_with_very_long_line_and_word(self): + self.assertEqual( [[' This is my very long line which my\n', ' very long line which\n', ' my_very_long_line_which_will_wrap_near_its_end,']], + self.wrap_plus._split_lines( + self.wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50, " " ) ) + + def test_balance_characters_between_line_wraps_with_trailing_new_line(self): + self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,\n'], + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, ["This is my very long line which will wrap near its end,\n"], " ", " " ) ) + + def test_balance_characters_between_line_wraps_without_trailing_new_line(self): + self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,'], + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, ["This is my very long line which will wrap near its end,"], " ", " " ) ) + + def test_balance_characters_between_line_wraps_ending_with_long_word(self): + self.wrap_plus._width = 80 + self.assertEqual( [' ', 'In this proposal last chapter which lies on the part\n', + " called `\\nameref{sec:software_implementation}',"], + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, [ "In this proposal last chapter which lies on the part called " + "`\\nameref{sec:software_implementation}'," ], " ", " " ) ) + + +class SemanticLineWrapUnitTests(unittest.TestCase): + + @classmethod + def setUp(self): + self.maxDiff = None + self.wrap_plus = wrap_plus_module.WrapLinesPlusCommand( None ) + self.wrap_plus._width = 80 + + global maximum_words_in_comma_separated_list + maximum_words_in_comma_separated_list = 4 + + def test_is_command_separated_list(self): + self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, True ) + self.is_comma_separated_list( "1_ 2, 3, 4_ 5", 4, True ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4, True ) + self.is_comma_separated_list( "1_ 2, 3_ 4, 5", 4, True ) + + def test_is_command_separated_list_upperbound(self): + self.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1, False ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6, 7", 4, False ) + self.is_comma_separated_list( "1_ 2, 3_ 4__5 6_ 7", 4, False ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6_ 7", 4, False ) + + def test_is_command_separated_list_lowerbound(self): + self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3, True ) + self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 3, True ) + self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 3, True ) + + def is_comma_separated_list(self, text, index, goal): + self.assertTrue( text[index] in wrap_plus_module.word_separator_characters ) + self.assertEqual( goal, self.wrap_plus.is_comma_separated_list( text, index, True )[0] + or self.wrap_plus.is_comma_separated_list( text, index, False )[0] ) + + def test_semantic_line_wrap_simple_sentences(self): + self.semantic_line_wrap( "1", "1" ) + self.semantic_line_wrap( "which will take, you quite some time", + "which will take,\nyou quite some time" ) + + self.semantic_line_wrap( "which will take, you, quite some time", + "which will take,\nyou, quite some time" ) + + def test_semantic_line_wrap_long_word(self): + self.semantic_line_wrap( "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime", + "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ) + + def test_semantic_line_wrap_ending_with_comma_list(self): + self.semantic_line_wrap( "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc.", + "you still only configuring a few languages closely related.\nOn this case, C, C++, Java, Pawn, etc." ) + + def test_semantic_line_wrap_with_comma_list_on_the_middle(self): + self.semantic_line_wrap( "which will not more take, you quite oh the time, some time, more time, the time, per time", + "which will not more take,\nyou quite oh the time,\nsome time, more time, the time, per time" ) + + def test_semantic_line_wrap_with_comma_list_on_the_end(self): + self.semantic_line_wrap( "few languages close related. On this case, C, C++, Java, Pawn, etc. more over break this line", + "few languages close related.\nOn this case, C, C++, Java, Pawn, etc.\nmore over break this line" ) + + def test_semantic_line_wrap_with_numeric_comma_list_on_the_end(self): + self.semantic_line_wrap( "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1", + "1 2 3 4.\n5 6 7, 1, 2, 3, 4, 5.\n6 7 8 9 1" ) + + def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): + self.semantic_line_wrap( "For all other languages you still need to find out another source code " + "formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/" + "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}", + + "For all other languages you still need to find out another source code " + "formatter\ntool,\nwhich will be certainly\nlimited\\footnote{\\url{https://stackoverflow.com/" + "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ) + + def test_semantic_line_wrap_with_80_characters(self): + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + "few languages close related.\nOn this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program,\nassure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) + + def test_semantic_line_wrap_with_79_characters(self): + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + "few languages close related.\nOn this case, C, C++, Java, Pawn, if, you, already, had, written, the, program,\nassure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) + + def test_semantic_line_wrap_with_81_characters(self): + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprogram, assure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) + + def test_semantic_line_wrap_with_81_characters_on_list_flushing(self): + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprograms, assure, everything, is, under, versioning, control, system, and,\nbroke, everything, etc.\nmore over break this line" ) + + def test_semantic_line_wrap_with_initial_indentation(self): + self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " + "which will be certainly limited and still need to configure all over again.", " ", " " ], + " For all other languages you still need to find out another source code f\n" + " tool,\n" + " which will be certainly limited and still need to configure all over again." ) + + def semantic_line_wrap(self, initial_text, goal): + + if isinstance( initial_text, list ): + self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text[0]], initial_text[1], initial_text[2] ) ) ) + + else: + self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) ) + + +def suite(classes, unit_tests_to_run): + """ + Problem with sys.argv[1] when unittest module is in a script + https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script + + Is there a way to loop through and execute all of the functions in a Python class? + https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute-all-of-the-functions + + looping over all member variables of a class in python + https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python + """ + suite = unittest.TestSuite() + unit_tests_to_run_count = len( unit_tests_to_run ) + + for _class in classes: + _object = _class() + + for function_name in dir( _object ): + + if function_name.lower().startswith( "test" ): + + if unit_tests_to_run_count > 0 \ + and function_name not in unit_tests_to_run: + + continue + + suite.addTest( _class( function_name ) ) + + return suite + + diff --git a/unittesting.json b/unittesting.json new file mode 100644 index 0000000..af1e7b3 --- /dev/null +++ b/unittesting.json @@ -0,0 +1,9 @@ +{ + "tests_dir" : "tests", + "pattern" : "*unit_tests.py", + "async": false, + "deferred": false, + "verbosity": 2, + "capture_console": false, + "output": null +} diff --git a/wrap_plus.py b/wrap_plus.py index 6b3238e..1106058 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1074,250 +1074,36 @@ def print_text_replacements(self, text, selection): debug('replaced text is the same') -def plugin_loaded(): - """ - Running single test from unittest.TestCase via command line - https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line - """ - pass - # print( "\n\n" ) - # run_unit_tests() - # run_manual_tests() - - -def run_unit_tests(): - runner = unittest.TextTestRunner() - - classes = \ - [ - SemanticLineWrapUnitTests, - LineBalancingUnitTests, - ] - - # Comment all the tests names on this list, to run all Unit Tests - unit_tests_to_run = \ - [ - # "test_split_lines_with_trailing_new_line", - # "test_split_lines_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_with_trailing_new_line", - # "test_balance_characters_between_line_wraps_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_ending_with_long_word", - ] +def reload_package(full_module_name): + import imp + import sys + import importlib - runner.run( suite( classes, unit_tests_to_run ) ) + if full_module_name in sys.modules: + module_object = sys.modules[full_module_name] + module_object = imp.reload( module_object ) + else: + importlib.import_module( full_module_name ) -def run_manual_tests(): - wrap_plus = WrapLinesPlusCommand( None ) - wrap_plus._width = 80 - # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "", balance_characters_between_line_wraps=True ) - # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) - # wrap_plus.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "", "" ) - # wrap_plus.semantic_line_wrap( [ "which will not more take, you quite oh the time, some time, more time, the time, per time" ], "", "" ) - # wrap_plus.semantic_line_wrap( [ "few languages closely related. On this case, C, C++, Java, Pawn, etc. more over break this line" ], "", "" ) - # wrap_plus.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "", "" ) - # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ], "", "" ) - # wrap_plus.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, which" ], " ", " " ) +def run_tests(): + print( "\n\n" ) + reload_package( "Wrap Plus.tests.semantic_linefeed_unit_tests" ) + reload_package( "Wrap Plus.tests.semantic_linefeed_manual_tests" ) - wrapper = textwrap.TextWrapper(break_long_words=False, break_on_hyphens=False) - wrap_plus = WrapLinesPlusCommand( None ) - wrap_plus._width = 50 - wrapper.expand_tabs = False - wrapper.subsequent_indent = " " + from .tests import semantic_linefeed_unit_tests + from .tests import semantic_linefeed_manual_tests - # wrap_plus._split_lines( wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50, " " ) - # wrap_plus._split_lines( wrapper, [ "This is my very long line which will wrap near its end,\n" ], 50, " " ) + semantic_linefeed_unit_tests.run_unit_tests() + semantic_linefeed_manual_tests.run_manual_tests() - # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,\n" ], " ", " " ) - # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,", "This is my very long line which will wrap near its end," ], " ", " " ) - wrap_plus._width = 80 - wrap_plus._split_lines( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], 80, " " ) - # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], " ", " " ) - - - -class LineBalancingUnitTests(unittest.TestCase): - - @classmethod - def setUp(self): - self.maxDiff = None - - self.wrap_plus = WrapLinesPlusCommand( None ) - self.wrap_plus._width = 50 - - self.wrapper = textwrap.TextWrapper(break_long_words=False, break_on_hyphens=False) - self.wrapper.subsequent_indent = " " - self.wrapper.expand_tabs = False - - global maximum_words_in_comma_separated_list - maximum_words_in_comma_separated_list = 4 - - def test_split_lines_without_trailing_new_line(self): - self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,']], - self.wrap_plus._split_lines( - self.wrapper, ["This is my very long line which will wrap near its end,"], 50, " " ) ) - - def test_split_lines_with_trailing_new_line(self): - self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,\n']], - self.wrap_plus._split_lines( - self.wrapper, ["This is my very long line which will wrap near its end,\n"], 50, " " ) ) - - def test_split_lines_with_very_long_line_and_word(self): - self.assertEqual( [[' This is my very long line which my\n', ' very long line which\n', ' my_very_long_line_which_will_wrap_near_its_end,']], - self.wrap_plus._split_lines( - self.wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50, " " ) ) - - def test_balance_characters_between_line_wraps_with_trailing_new_line(self): - self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,\n'], - self.wrap_plus.balance_characters_between_line_wraps( - self.wrapper, ["This is my very long line which will wrap near its end,\n"], " ", " " ) ) - - def test_balance_characters_between_line_wraps_without_trailing_new_line(self): - self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,'], - self.wrap_plus.balance_characters_between_line_wraps( - self.wrapper, ["This is my very long line which will wrap near its end,"], " ", " " ) ) - - def test_balance_characters_between_line_wraps_ending_with_long_word(self): - self.wrap_plus._width = 80 - self.assertEqual( [' ', 'In this proposal last chapter which lies on the part\n', - " called `\\nameref{sec:software_implementation}',"], - self.wrap_plus.balance_characters_between_line_wraps( - self.wrapper, [ "In this proposal last chapter which lies on the part called " - "`\\nameref{sec:software_implementation}'," ], " ", " " ) ) - - -class SemanticLineWrapUnitTests(unittest.TestCase): - - @classmethod - def setUp(self): - self.maxDiff = None - self.wrap_plus = WrapLinesPlusCommand( None ) - self.wrap_plus._width = 80 - - global maximum_words_in_comma_separated_list - maximum_words_in_comma_separated_list = 4 - - def test_is_command_separated_list(self): - self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, True ) - self.is_comma_separated_list( "1_ 2, 3, 4_ 5", 4, True ) - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4, True ) - self.is_comma_separated_list( "1_ 2, 3_ 4, 5", 4, True ) - - def test_is_command_separated_list_upperbound(self): - self.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1, False ) - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6, 7", 4, False ) - self.is_comma_separated_list( "1_ 2, 3_ 4__5 6_ 7", 4, False ) - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6_ 7", 4, False ) - - def test_is_command_separated_list_lowerbound(self): - self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3, True ) - self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 3, True ) - self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 3, True ) - - def is_comma_separated_list(self, text, index, goal): - self.assertTrue( text[index] in word_separator_characters ) - self.assertEqual( goal, self.wrap_plus.is_comma_separated_list( text, index, True )[0] - or self.wrap_plus.is_comma_separated_list( text, index, False )[0] ) - - def test_semantic_line_wrap_simple_sentences(self): - self.semantic_line_wrap( "1", "1" ) - self.semantic_line_wrap( "which will take, you quite some time", - "which will take,\nyou quite some time" ) - - self.semantic_line_wrap( "which will take, you, quite some time", - "which will take,\nyou, quite some time" ) - - def test_semantic_line_wrap_long_word(self): - self.semantic_line_wrap( "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime", - "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ) - - def test_semantic_line_wrap_ending_with_comma_list(self): - self.semantic_line_wrap( "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc.", - "you still only configuring a few languages closely related.\nOn this case, C, C++, Java, Pawn, etc." ) - - def test_semantic_line_wrap_with_comma_list_on_the_middle(self): - self.semantic_line_wrap( "which will not more take, you quite oh the time, some time, more time, the time, per time", - "which will not more take,\nyou quite oh the time,\nsome time, more time, the time, per time" ) - - def test_semantic_line_wrap_with_comma_list_on_the_end(self): - self.semantic_line_wrap( "few languages close related. On this case, C, C++, Java, Pawn, etc. more over break this line", - "few languages close related.\nOn this case, C, C++, Java, Pawn, etc.\nmore over break this line" ) - - def test_semantic_line_wrap_with_numeric_comma_list_on_the_end(self): - self.semantic_line_wrap( "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1", - "1 2 3 4.\n5 6 7, 1, 2, 3, 4, 5.\n6 7 8 9 1" ) - - def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): - self.semantic_line_wrap( "For all other languages you still need to find out another source code " - "formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/" - "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}", - - "For all other languages you still need to find out another source code " - "formatter\ntool,\nwhich will be certainly\nlimited\\footnote{\\url{https://stackoverflow.com/" - "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ) - - def test_semantic_line_wrap_with_80_characters(self): - self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], - "few languages close related.\nOn this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program,\nassure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) - - def test_semantic_line_wrap_with_79_characters(self): - self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], - "few languages close related.\nOn this case, C, C++, Java, Pawn, if, you, already, had, written, the, program,\nassure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) - - def test_semantic_line_wrap_with_81_characters(self): - self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], - "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprogram, assure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) - - def test_semantic_line_wrap_with_81_characters_on_list_flushing(self): - self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], - "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprograms, assure, everything, is, under, versioning, control, system, and,\nbroke, everything, etc.\nmore over break this line" ) - - def test_semantic_line_wrap_with_initial_indentation(self): - self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " - "which will be certainly limited and still need to configure all over again.", " ", " " ], - " For all other languages you still need to find out another source code f\n" - " tool,\n" - " which will be certainly limited and still need to configure all over again." ) - - def semantic_line_wrap(self, initial_text, goal): - - if isinstance( initial_text, list ): - self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text[0]], initial_text[1], initial_text[2] ) ) ) - - else: - self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) ) - - -def suite(classes, unit_tests_to_run): +def plugin_loaded(): """ - Problem with sys.argv[1] when unittest module is in a script - https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script - - Is there a way to loop through and execute all of the functions in a Python class? - https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute-all-of-the-functions - - looping over all member variables of a class in python - https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python + Running single test from unittest.TestCase via command line + https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line """ - suite = unittest.TestSuite() - unit_tests_to_run_count = len( unit_tests_to_run ) - - for _class in classes: - _object = _class() - - for function_name in dir( _object ): - - if function_name.lower().startswith( "test" ): - - if unit_tests_to_run_count > 0 \ - and function_name not in unit_tests_to_run: - - continue - - suite.addTest( _class( function_name ) ) - - return suite - + # run_tests() + pass From 7b1c0cc385991bc2fdd40bd93224568c4eec68d6 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 16:42:57 -0200 Subject: [PATCH 035/160] Prefixed the semantic linefeed settings with WrapPlus.semantic_ --- Base File.sublime-settings | 8 ++++---- wrap_plus.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 2f00655..9fddf90 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -23,7 +23,7 @@ // will wrap near its end, // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. - "WrapPlus.balance_characters_between_line_wraps": true, + "WrapPlus.semantic_balance_characters_between_line_wraps": true, // The minimum of the percentage of the current maximum line width a line can // have. For example, if you `wrap_width` is set to 100, and you set this to `0.2`, @@ -34,13 +34,13 @@ // to disable the minimum width and always wrap the lines despite their size. // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. - "WrapPlus.minimum_line_size_percent": 0.0, + "WrapPlus.semantic_minimum_line_size_percent": 0.0, // When wrapping lines, it will consider they to be a list of words if between // two sequential commas is find at the maximum these number of words. // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. - "WrapPlus.maximum_words_in_comma_separated_list": 3, + "WrapPlus.semantic_maximum_words_in_comma_separated_list": 3, // The `semantic_line_wrap` detects the maximum line width and uses it to // limite/delimite the maximum line width. If you like your lines only to be @@ -49,7 +49,7 @@ // * This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. // * If the setting `WrapPlus.balance_characters_between_line_wraps` is enabled, // this setting will be ignored. - "WrapPlus.disable_line_wrapping_by_maximum_width": false, + "WrapPlus.semantic_disable_line_wrapping_by_maximum_width": false, // Determines whether or not line endings are included in the line size: // - true: Always included. diff --git a/wrap_plus.py b/wrap_plus.py index 1106058..b909e18 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -661,10 +661,10 @@ def run(self, edit, width=0): break_long_words = view_settings.get('WrapPlus.break_long_words', True) break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) - minimum_line_size_percent = view_settings.get('WrapPlus.minimum_line_size_percent', 0.2) - balance_characters_between_line_wraps = view_settings.get('WrapPlus.balance_characters_between_line_wraps', False) - disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.disable_line_wrapping_by_maximum_width', False) - maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.maximum_words_in_comma_separated_list', 3) + 1 + minimum_line_size_percent = view_settings.get('WrapPlus.semantic_minimum_line_size_percent', 0.2) + balance_characters_between_line_wraps = view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) + disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.semantic_disable_line_wrapping_by_maximum_width', False) + maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) From 1ca086c384b817a75fab61b38ea343707b32e313 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 16:46:15 -0200 Subject: [PATCH 036/160] Moved the WrapLinesEnhancementAskCommand to the file wrap_plus.py --- WrapPlus.sublime-commands | 2 +- wrap_lines_enhancement.py | 17 ----------------- wrap_plus.py | 17 +++++++++++++++++ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/WrapPlus.sublime-commands b/WrapPlus.sublime-commands index b14e38d..beb35fa 100644 --- a/WrapPlus.sublime-commands +++ b/WrapPlus.sublime-commands @@ -1,6 +1,6 @@ [ { "caption": "Wrap Plus: Wrap Lines","command": "wrap_lines_plus" }, - { "caption": "Wrap Plus: Wrap Lines at ... chars (Ask)", "command": "wrap_lines_enhancement_ask" }, + { "caption": "Wrap Plus: Wrap Lines at ... chars", "command": "wrap_lines_enhancement_ask" }, { "caption": "Wrap Plus: Wrap Lines at 65 chars", "command": "wrap_lines_enhancement", "args": { "width": 65 } }, { "caption": "Wrap Plus: Wrap Lines at 70 chars", "command": "wrap_lines_enhancement", "args": { "width": 70 } }, diff --git a/wrap_lines_enhancement.py b/wrap_lines_enhancement.py index cc83cfc..fb02aef 100644 --- a/wrap_lines_enhancement.py +++ b/wrap_lines_enhancement.py @@ -20,20 +20,3 @@ def run(self, edit, **kwargs): self.view.sel().add(sublime.Region(pos)) -last_used_width = 80 - -class WrapLinesEnhancementAskCommand(sublime_plugin.TextCommand): - - def run(self, edit, **kwargs): - sublime.active_window().show_input_panel( - 'Provide wrapping width:', str( last_used_width ), - self.input_package, None, None - ) - - def input_package(self, width): - global last_used_width - - last_used_width = width - self.view.run_command('wrap_lines_plus', { 'width': int( width ) } ) - - diff --git a/wrap_plus.py b/wrap_plus.py index b909e18..4763238 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1074,6 +1074,23 @@ def print_text_replacements(self, text, selection): debug('replaced text is the same') +last_used_width = 80 + +class WrapLinesEnhancementAskCommand(sublime_plugin.TextCommand): + + def run(self, edit, **kwargs): + sublime.active_window().show_input_panel( + 'Provide wrapping width:', str( last_used_width ), + self.input_package, None, None + ) + + def input_package(self, width): + global last_used_width + + last_used_width = width + self.view.run_command( 'wrap_lines_plus', { 'width': int( width ) } ) + + def reload_package(full_module_name): import imp import sys From c2a225041b749beb007fc947ee8d3bd849d573ca Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 17:10:26 -0200 Subject: [PATCH 037/160] Deprecated the wrap_lines_enhancement.py file and create the new setting "WrapPlus.after_wrap" to control the cursor behavior while wrapping the text. It accepts the following: "cursor_below", will move the cursor/caret to the end the the wrapped text. "cursor_stay", will `attempt` to keep the cursor/caret on its original position. --- Base File.sublime-settings | 6 ++++++ Default (Linux).sublime-keymap | 2 +- Default (OSX).sublime-keymap | 2 +- Default (Windows).sublime-keymap | 2 +- WrapPlus.sublime-commands | 10 +++++----- wrap_lines_enhancement.py | 22 ---------------------- wrap_plus.py | 24 +++++++++++++++++++----- 7 files changed, 33 insertions(+), 35 deletions(-) delete mode 100644 wrap_lines_enhancement.py diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 9fddf90..b9caffc 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -6,6 +6,12 @@ // If true, will break on hyphens in compound words. "WrapPlus.break_on_hyphens": false, + // Control the cursor behavior while wrapping the text. It accepts the following: + // + // "cursor_below", will move the cursor/caret to the end the the wrapped text + // "cursor_stay", will `attempt` to keep the cursor/caret on its original position + "WrapPlus.after_wrap": "cursor_stay", + // If true, the semantic linewrap also know as semantic linefeed will be used. // See the following address for more descriptions: // http://rhodesmill.org/brandon/2012/one-sentence-per-line/ diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index 26820a9..7b60e25 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -1,3 +1,3 @@ [ - { "keys": ["alt+q"], "command": "wrap_lines_enhancement" } + { "keys": ["alt+q"], "command": "wrap_lines_plus" } ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index ee70264..a488ae9 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -1,3 +1,3 @@ [ - { "keys": ["super+alt+q"], "command": "wrap_lines_enhancement" } + { "keys": ["super+alt+q"], "command": "wrap_lines_plus" } ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index 26820a9..7b60e25 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -1,3 +1,3 @@ [ - { "keys": ["alt+q"], "command": "wrap_lines_enhancement" } + { "keys": ["alt+q"], "command": "wrap_lines_plus" } ] diff --git a/WrapPlus.sublime-commands b/WrapPlus.sublime-commands index beb35fa..2ce4f3f 100644 --- a/WrapPlus.sublime-commands +++ b/WrapPlus.sublime-commands @@ -2,9 +2,9 @@ { "caption": "Wrap Plus: Wrap Lines","command": "wrap_lines_plus" }, { "caption": "Wrap Plus: Wrap Lines at ... chars", "command": "wrap_lines_enhancement_ask" }, - { "caption": "Wrap Plus: Wrap Lines at 65 chars", "command": "wrap_lines_enhancement", "args": { "width": 65 } }, - { "caption": "Wrap Plus: Wrap Lines at 70 chars", "command": "wrap_lines_enhancement", "args": { "width": 70 } }, - { "caption": "Wrap Plus: Wrap Lines at 72 chars", "command": "wrap_lines_enhancement", "args": { "width": 72 } }, - { "caption": "Wrap Plus: Wrap Lines at 80 chars", "command": "wrap_lines_enhancement", "args": { "width": 80 } }, - { "caption": "Wrap Plus: Wrap Lines at 100 chars", "command": "wrap_lines_enhancement", "args": { "width": 100 } }, + { "caption": "Wrap Plus: Wrap Lines at 65 chars", "command": "wrap_lines_plus", "args": { "width": 65 } }, + { "caption": "Wrap Plus: Wrap Lines at 70 chars", "command": "wrap_lines_plus", "args": { "width": 70 } }, + { "caption": "Wrap Plus: Wrap Lines at 72 chars", "command": "wrap_lines_plus", "args": { "width": 72 } }, + { "caption": "Wrap Plus: Wrap Lines at 80 chars", "command": "wrap_lines_plus", "args": { "width": 80 } }, + { "caption": "Wrap Plus: Wrap Lines at 100 chars", "command": "wrap_lines_plus", "args": { "width": 100 } }, ] diff --git a/wrap_lines_enhancement.py b/wrap_lines_enhancement.py deleted file mode 100644 index fb02aef..0000000 --- a/wrap_lines_enhancement.py +++ /dev/null @@ -1,22 +0,0 @@ - - -import sublime, sublime_plugin - -class WrapLinesEnhancementCommand(sublime_plugin.TextCommand): - """ - Wrap without loosing cursor position - https://github.com/ehuss/Sublime-Wrap-Plus/issues/19 - - My workaround is simple. Create a new plugin with the following implementations: - https://github.com/ggutierrez - """ - - def run(self, edit, **kwargs): - - pos = self.view.sel()[0].begin() - - self.view.run_command('wrap_lines_plus', kwargs) - self.view.sel().clear() - self.view.sel().add(sublime.Region(pos)) - - diff --git a/wrap_plus.py b/wrap_plus.py index 4763238..2539cc8 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -641,18 +641,21 @@ def run(self, edit, width=0): debug_start(self.view.settings().get('WrapPlus.debug', False)) debug('\n\n#########################################################################') + cursor_original_positions = [] self._width = self._determine_width(width) - # print('wrap width = %r', self._width) + # print('wrap width = %r', self._width) self._determine_tab_size() self._determine_comment_style() # paragraphs is a list of (region, lines, comment_prefix) tuples. paragraphs = [] - for s in self.view.sel(): - debug('examine %r', s) - paragraphs.extend(self._find_paragraphs(s)) + for selection in self.view.sel(): + debug('examine %r', selection) + + paragraphs.extend(self._find_paragraphs(selection)) + cursor_original_positions.append(selection.begin()) view_settings = self.view.settings() debug('paragraphs is %r', paragraphs) @@ -660,6 +663,7 @@ def run(self, edit, width=0): global maximum_words_in_comma_separated_list break_long_words = view_settings.get('WrapPlus.break_long_words', True) break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) + after_wrap = view_settings.get('WrapPlus.after_wrap', "cursor_below") minimum_line_size_percent = view_settings.get('WrapPlus.semantic_minimum_line_size_percent', 0.2) balance_characters_between_line_wraps = view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) @@ -715,7 +719,11 @@ def line_wrapper_type(): self.view.replace(edit, selection, text) self.print_text_replacements(text, selection) - self.move_cursor_below_the_last_paragraph() + if after_wrap == "cursor_below": + self.move_cursor_below_the_last_paragraph() + + else: + self.move_the_cursor_to_the_original_position(cursor_original_positions) def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_prefix, subsequent_prefix): """ @@ -1065,6 +1073,12 @@ def move_cursor_below_the_last_paragraph(self): self.view.show(region) debug_end() + def move_the_cursor_to_the_original_position(self, cursor_original_positions): + self.view.sel().clear() + + for position in cursor_original_positions: + self.view.sel().add( sublime.Region( position, position ) ) + def print_text_replacements(self, text, selection): replaced_txt = self.view.substr(selection) From de7905a50014a3db384afc045169533561f561f1 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 17:25:18 -0200 Subject: [PATCH 038/160] Added reference to How do I unload (reload) a Python module? on wrap_plus.py --- wrap_plus.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wrap_plus.py b/wrap_plus.py index 2539cc8..aac29b1 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1119,6 +1119,10 @@ def reload_package(full_module_name): def run_tests(): + """ + How do I unload (reload) a Python module? + https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module + """ print( "\n\n" ) reload_package( "Wrap Plus.tests.semantic_linefeed_unit_tests" ) reload_package( "Wrap Plus.tests.semantic_linefeed_manual_tests" ) From b5ec72d4c8feef8e72fb466fd61ed6f7e2bd0cdd Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 9 Nov 2017 17:36:28 -0200 Subject: [PATCH 039/160] Removed deprecated message from README.md and added instructions to run the unit tests. --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ad837a7..d973758 100644 --- a/README.md +++ b/README.md @@ -193,14 +193,17 @@ Wrap Plus handles a lot of situations that the stock Sublime word wrapper doesn' -# Wrap Plus Enhanced +## Unit Tests +To run the unit tests: -The file `wrap_lines_enhancement.py` is a wrapper around the default command `wrap_lines_plus` which -does add the following fix from the issue: +1. Install the package: https://github.com/randy3k/UnitTesting +1. Open the file `unit_testing/override_commmit_completions_unit_tests.py` +1. Open the Sublime Text command palette with `Ctrl+Shift+P` +1. And run the command: `UnitTesting: Test Current Package` -(Wrap without loosing cursor position) -https://github.com/ehuss/Sublime-Wrap-Plus/issues/19 +Or you can just uncomment the line `# run_tests()` on the function `plugin_loaded()` at the end of +the file. The results are going to be displayed on the `Sublime Text Console`. ## License From 4f21c6b12c2ea31e16d7aef93573eba37a456b90 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 17 Nov 2017 14:36:40 -0200 Subject: [PATCH 040/160] When using the generic syntax, the Sublime Text plugin `Default.comment` will return the default syntax comment prefix `#` instead of the actual line prefix. --- wrap_plus.py | 281 +++++++++++++++++++++++++++------------------------ 1 file changed, 148 insertions(+), 133 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index aac29b1..1f79875 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -11,7 +11,7 @@ import comment -def is_quoted_string(scope_r, scope_name): +def is_quoted_string(scope_region, scope_name): # string.quoted.double.block.python # string.quoted.single.block.python # string.quoted.double.single-line.python @@ -68,75 +68,90 @@ def __init__(self, view, min, max): def _is_c_comment(self, scope_name): if not 'comment' in scope_name and not 'block' in scope_name: return False - for start, end, disable_indent in self.bc: + for start, end, disable_indent in self.block_comment: if start == '/*' and end == '*/': break else: return False return True - def set_comments(self, lc, bc, pt): - self.lc = lc - self.bc = bc - # If the line at pt is a comment line, set required_comment_prefix to + def set_comments(self, line_comments, block_comment, point): + self.line_comments = line_comments + self.block_comment = block_comment + + scope_region = self.view.extract_scope(point) + scope_name = self.view.scope_name(point) + + # If the line at point is a comment line, set required_comment_prefix to # the comment prefix. self.required_comment_prefix = '' + # Grab the line. - line_r = self.view.line(pt) - line = self.view.substr(line_r) - line_strp = line.strip() - if not line_strp: + line_region = self.view.line(point) + line = self.view.substr(line_region) + line_stripped = line.strip() + + if not line_stripped: # Empty line, nothing to do. debug('Empty line, no comment characters found.') return - # Determine if pt is inside a "line comment". + # Determine if point is inside a "line comment". # Only whitespace is allowed to the left of the line comment. - # XXX: What is disable_indent? - for start, disable_indent in lc: - start = start.rstrip() - if line_strp.startswith(start): - ldiff = len(line) - len(line.lstrip()) - p = line[:ldiff+len(start)] + is_generic_config = "source.genconfig" in scope_name + debug( "line_comments: " + str( line_comments ) ) + + # When using the generic syntax, the Sublime Text plugin `Default.comment` will return + # the default syntax comment prefix `#` instead of the actual line prefix + if is_generic_config: + line_comments.extend([("//", False), ("#", False), ("%", False)]) + + for line_comment, is_block_comment in line_comments: + line_comment = line_comment.rstrip() + debug( ( "line_comment: %s, line_stripped: %s" % ( line_comment, line_stripped ) ).replace("%", "%%") ) + + if line_stripped.startswith(line_comment): + + line_difference = len(line) - len(line.lstrip()) + prefix = line[:line_difference+len(line_comment)] + if self.required_comment_prefix is None or \ - len(self.required_comment_prefix) < len(p): - self.required_comment_prefix = p + len(self.required_comment_prefix) < len(prefix): + self.required_comment_prefix = prefix # TODO: re.escape required_comment_prefix. # Handle email-style quoting. email_quote_pattern = re.compile('^' + self.required_comment_prefix + email_quote) - m = email_quote_pattern.match(line) - if m: - self.required_comment_prefix = m.group() + regex_match = email_quote_pattern.match(line) + if regex_match: + self.required_comment_prefix = regex_match.group() self.required_comment_pattern = email_quote_pattern debug('doing email style quoting') - scope_r = self.view.extract_scope(pt) - scope_name = self.view.scope_name(pt) - debug('scope=%r range=%r', scope_name, scope_r) + debug('scope=%r range=%r', scope_name, scope_region) if self._is_c_comment(scope_name): # Check for C-style commenting with each line starting with an asterisk. first_star_prefix = None - lines = self.view.lines(scope_r) - for line_r in lines[1:-1]: - line = self.view.substr(line_r) - m = funny_c_comment_pattern.match(line) - if m != None: + lines = self.view.lines(scope_region) + for line_region in lines[1:-1]: + line = self.view.substr(line_region) + regex_match = funny_c_comment_pattern.match(line) + if regex_match != None: if first_star_prefix == None: - first_star_prefix = m.group() + first_star_prefix = regex_match.group() else: first_star_prefix = None break if first_star_prefix: self.required_comment_prefix = first_star_prefix # Narrow the scope to just the comment contents. - scope_text = self.view.substr(scope_r) - m = re.match(r'^([ \t\n]*/\*).*(\*/[ \t\n]*)$', scope_text, re.DOTALL) - if m: - begin = scope_r.begin() + len(m.group(1)) - end = scope_r.end() - len(m.group(2)) + scope_text = self.view.substr(scope_region) + regex_match = re.match(r'^([ \t\n]*/\*).*(\*/[ \t\n]*)$', scope_text, re.DOTALL) + if regex_match: + begin = scope_region.begin() + len(regex_match.group(1)) + end = scope_region.end() - len(regex_match.group(2)) self.min = max(self.min, begin) self.max = min(self.max, end) debug('Scope narrowed to %i:%i', self.min, self.max) @@ -144,24 +159,24 @@ def set_comments(self, lc, bc, pt): debug('required_comment_prefix determined to be %r', self.required_comment_prefix,) # Narrow the min/max range if inside a "quoted" string. - if is_quoted_string(scope_r, scope_name): + if is_quoted_string(scope_region, scope_name): # Narrow the range. - self.min = max(self.min, self.view.line(scope_r.begin()).begin()) - self.max = min(self.max, self.view.line(scope_r.end()).end()) + self.min = max(self.min, self.view.line(scope_region.begin()).begin()) + self.max = min(self.max, self.view.line(scope_region.end()).end()) def line(self, where): """Get a line for a point. :returns: A (region, str) tuple. str has the comment prefix stripped. """ - line_r = self.view.line(where) - if line_r.begin() < self.min: + line_region = self.view.line(where) + if line_region.begin() < self.min: debug('line min increased') - line_r = sublime.Region(self.min, line_r.end()) - if line_r.end() > self.max: + line_region = sublime.Region(self.min, line_region.end()) + if line_region.end() > self.max: debug('line max lowered') - line_r = sublime.Region(line_r.begin(), self.max) - line = self.view.substr(line_r) + line_region = sublime.Region(line_region.begin(), self.max) + line = self.view.substr(line_region) debug('line=%r', line) if self.required_comment_prefix: debug('checking required comment prefix %r', self.required_comment_prefix) @@ -169,9 +184,9 @@ def line(self, where): if line.startswith(self.required_comment_prefix): # Check for an insufficient prefix. if self.required_comment_pattern: - m = self.required_comment_pattern.match(line) - if m: - if m.group() != self.required_comment_prefix: + regex_match = self.required_comment_pattern.match(line) + if regex_match: + if regex_match.group() != self.required_comment_prefix: # This might happen, if for example with an email # comment, we go from one comment level to a # deeper one (the regex matched more > characters @@ -183,10 +198,10 @@ def line(self, where): return None, None l = len(self.required_comment_prefix) line = line[l:] - # XXX: Should this also update line_r? + # XXX: Should this also update line_region? else: return None, None - return line_r, line + return line_region, line def substr(self, r): return self.view.substr(r) @@ -194,18 +209,18 @@ def substr(self, r): def next_line(self, where): l_r = self.view.line(where) debug('next line region=%r', l_r) - pt = l_r.end()+1 - if pt >= self.max: + point = l_r.end()+1 + if point >= self.max: debug('past max at %r', self.max) return None, None - return self.line(pt) + return self.line(point) def prev_line(self, where): l_r = self.view.line(where) - pt = l_r.begin()-1 - if pt <= self.min: + point = l_r.begin()-1 + if point <= self.min: return None, None - return self.line(pt) + return self.line(point) def OR(*args): return '(?:' + '|'.join(args) + ')' @@ -262,7 +277,7 @@ def _my_full_line(self, region): else: return self.view.full_line(region) - def _is_paragraph_start(self, line_r, line): + def _is_paragraph_start(self, line_region, line): # Certain patterns at the beginning of the line indicate this is the # beginning of a paragraph. @@ -270,14 +285,14 @@ def _is_paragraph_start(self, line_r, line): # print( "new_paragraph_pattern.match(line): " + str( new_paragraph_pattern.match(line) ) ) return new_paragraph_pattern.match(line) != None - def _is_paragraph_break(self, line_r, line, pure=False): + def _is_paragraph_break(self, line_region, line, pure=False): """A paragraph "break" is something like a blank line, or a horizontal line, or anything that should not be wrapped and treated like a blank line (i.e. ignored). """ if self._is_blank_line(line): return True - scope_name = self.view.scope_name(line_r.begin()) - debug('scope_name=%r (%r)', scope_name, line_r) + scope_name = self.view.scope_name(line_region.begin()) + debug('scope_name=%r (%r)', scope_name, line_region) if 'heading' in scope_name: return True if pure: @@ -288,29 +303,29 @@ def _is_paragraph_break(self, line_r, line, pure=False): def _is_blank_line(self, line): return blank_line_pattern.match(line) != None - def _find_paragraph_start(self, pt): - """Start at pt and move up to find where the paragraph starts. + def _find_paragraph_start(self, point): + """Start at point and move up to find where the paragraph starts. :returns: The (line, line_region) of the start of the paragraph. """ view = self._strip_view - current_line_r, current_line = view.line(pt) - started_in_comment = self._started_in_comment(pt) + current_line_region, current_line = view.line(point) + started_in_comment = self._started_in_comment(point) debug('is_paragraph_break?') - if self._is_paragraph_break(current_line_r, current_line): - return current_line_r, current_line + if self._is_paragraph_break(current_line_region, current_line): + return current_line_region, current_line debug('no') while 1: # Check if this line is the start of a paragraph. debug('start?') - if self._is_paragraph_start(current_line_r, current_line): + if self._is_paragraph_start(current_line_region, current_line): debug('current_line is paragraph start: %r', current_line,) break # Check if the previous line is a "break" separator. debug('break?') - prev_line_r, prev_line = view.prev_line(current_line_r) + prev_line_r, prev_line = view.prev_line(current_line_region) if prev_line_r == None: # current_line is as far up as we're allowed to go. break @@ -329,9 +344,9 @@ def _find_paragraph_start(self, pt): debug('prev_line %r is part of the paragraph', prev_line,) # Previous line is a part of this paragraph. Add it, and loop # around again. - current_line_r = prev_line_r + current_line_region = prev_line_r current_line = prev_line - return current_line_r, current_line + return current_line_region, current_line def _find_paragraphs(self, sr): """Find and return a list of paragraphs as regions. @@ -361,75 +376,75 @@ def _find_paragraphs(self, sr): paragraph_start_pt = sr.begin() while 1: debug('paragraph scanning start %r.', paragraph_start_pt,) - view.set_comments(self._lc, self._bc, paragraph_start_pt) + view.set_comments(self._line_comment, self._is_block_comment, paragraph_start_pt) lines = [] if is_empty: # Find the beginning of this paragraph. debug('empty sel finding paragraph start.') - current_line_r, current_line = self._find_paragraph_start(paragraph_start_pt) - debug('empty sel paragraph start determined to be %r %r', current_line_r, current_line) + current_line_region, current_line = self._find_paragraph_start(paragraph_start_pt) + debug('empty sel paragraph start determined to be %r %r', current_line_region, current_line) else: # The selection defines the beginning. - current_line_r, current_line = view.line(paragraph_start_pt) - debug('sel beggining = %r %r', current_line_r, current_line) + current_line_region, current_line = view.line(paragraph_start_pt) + debug('sel beggining = %r %r', current_line_region, current_line) # Skip blank and unambiguous break lines. while 1: debug('skip blank line') - if not self._is_paragraph_break(current_line_r, current_line, pure=True): + if not self._is_paragraph_break(current_line_region, current_line, pure=True): debug('not paragraph break') break if is_empty: debug('empty sel on paragraph break %r', current_line,) return [] - current_line_r, current_line = view.next_line(current_line_r) + current_line_region, current_line = view.next_line(current_line_region) - paragraph_start_pt = current_line_r.begin() - paragraph_end_pt = current_line_r.end() - # current_line_r now points to the beginning of the paragraph. + paragraph_start_pt = current_line_region.begin() + paragraph_end_pt = current_line_region.end() + # current_line_region now points to the beginning of the paragraph. # Move down until the end of the paragraph. debug('Scan until end of paragraph.') while 1: - debug('current_line_r=%r max=%r', current_line_r, view.max) + debug('current_line_region=%r max=%r', current_line_region, view.max) # If we started in a non-comment scope, and the end of the # line contains a comment, include any non-comment text in the # wrap and stop looking for more. if (not started_in_comment and - self.view.score_selector(current_line_r.end(), 'comment') + self.view.score_selector(current_line_region.end(), 'comment') ): debug('end of paragraph hit a comment.') # Find the start of the comment. # This assumes comments do not have multiple scopes. - comment_r = self.view.extract_scope(current_line_r.end()) + comment_r = self.view.extract_scope(current_line_region.end()) # Just in case something is wonky with the scope. - end_pt = max(comment_r.begin(), current_line_r.begin()) + end_pt = max(comment_r.begin(), current_line_region.begin()) # A substring of current_line. - subline_r = sublime.Region(current_line_r.begin(), end_pt) + subline_r = sublime.Region(current_line_region.begin(), end_pt) subline = self.view.substr(subline_r) # Do not include whitespace preceding the comment. - m = re.search('([ \t]+$)', subline) - if m: - end_pt -= len(m.group(1)) + regex_match = re.search('([ \t]+$)', subline) + if regex_match: + end_pt -= len(regex_match.group(1)) debug('non-comment contents are: %r', subline) paragraph_end_pt = end_pt lines.append(subline) # Skip over the comment. - current_line_r, current_line = view.next_line(current_line_r) + current_line_region, current_line = view.next_line(current_line_region) break lines.append(current_line) - paragraph_end_pt = current_line_r.end() + paragraph_end_pt = current_line_region.end() - current_line_r, current_line = view.next_line(current_line_r) - if current_line_r == None: + current_line_region, current_line = view.next_line(current_line_region) + if current_line_region == None: # Line is outside of our range. debug('Out of range, stopping.') break - debug('current_line = %r %r', current_line_r, current_line) - if self._is_paragraph_break(current_line_r, current_line): + debug('current_line = %r %r', current_line_region, current_line) + if self._is_paragraph_break(current_line_region, current_line): debug('current line is a break, stopping.') break - if self._is_paragraph_start(current_line_r, current_line): + if self._is_paragraph_start(current_line_region, current_line): debug('current line is a paragraph start, stopping.') break @@ -443,19 +458,19 @@ def _find_paragraphs(self, sr): # Skip over blank lines and break lines till the next paragraph # (or end of range). debug('skip over blank lines') - while current_line_r != None: - if self._is_paragraph_start(current_line_r, current_line): + while current_line_region != None: + if self._is_paragraph_start(current_line_region, current_line): break - if not self._is_paragraph_break(current_line_r, current_line): + if not self._is_paragraph_break(current_line_region, current_line): break # It's a paragraph break, skip over it. - current_line_r, current_line = view.next_line(current_line_r) + current_line_region, current_line = view.next_line(current_line_region) - if current_line_r == None: + if current_line_region == None: break - debug('next_paragraph_start is %r %r', current_line_r, current_line) - paragraph_start_pt = current_line_r.begin() + debug('next_paragraph_start is %r %r', current_line_region, current_line) + paragraph_start_pt = current_line_region.begin() if paragraph_start_pt >= view_max: break @@ -534,18 +549,18 @@ def _determine_comment_style(self): # I'm not exactly sure why this function needs a point. It seems to # return the same value regardless of location for the stuff I've # tried. - (self._lc, self._bc) = comment.build_comment_data(self.view, 0) + (self._line_comment, self._is_block_comment) = comment.build_comment_data(self.view, 0) def _started_in_comment(self, point): if self.view.score_selector(point, 'comment'): return True # Check for case where only whitespace is before a comment. - line_r = self.view.line(point) - if self.view.score_selector(line_r.end(), 'comment'): - line = self.view.substr(line_r) - m = re.search('(^[ \t]+)', line) - if m: - pt_past_space = line_r.begin() + len(m.group(1)) + line_region = self.view.line(point) + if self.view.score_selector(line_region.end(), 'comment'): + line = self.view.substr(line_region) + regex_match = re.search('(^[ \t]+)', line) + if regex_match: + pt_past_space = line_region.begin() + len(regex_match.group(1)) if self.view.score_selector(pt_past_space, 'comment'): return True return False @@ -568,37 +583,37 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): initial_prefix = '' subsequent_prefix = '' first_line = lines[0] - m = list_pattern.match(first_line) - if m: - initial_prefix = first_line[0:m.end()] + regex_match = list_pattern.match(first_line) + if regex_match: + initial_prefix = first_line[0:regex_match.end()] stripped_prefix = initial_prefix.lstrip() leading_whitespace = initial_prefix[:len(initial_prefix)-len(stripped_prefix)] subsequent_prefix = leading_whitespace+' '*self._width_in_spaces(stripped_prefix) else: - m = field_pattern.match(first_line) - if m: + regex_match = field_pattern.match(first_line) + if regex_match: # The spaces in front of the field start. - initial_prefix = m.group(1) + initial_prefix = regex_match.group(1) if len(lines) > 1: # How to handle subsequent lines. - m = space_prefix_pattern.match(lines[1]) - if m: + regex_match = space_prefix_pattern.match(lines[1]) + if regex_match: # It's already indented, keep this indent level # (unless it is less than where the field started). - spaces = m.group(0) + spaces = regex_match.group(0) if self._width_in_spaces(spaces) >= self._width_in_spaces(initial_prefix)+1: subsequent_prefix = spaces if not subsequent_prefix: # Not already indented, make an indent. subsequent_prefix = initial_prefix + self._make_indent() else: - m = space_prefix_pattern.match(first_line) - if m: - initial_prefix = first_line[0:m.end()] + regex_match = space_prefix_pattern.match(first_line) + if regex_match: + initial_prefix = first_line[0:regex_match.end()] if len(lines) > 1: - m = space_prefix_pattern.match(lines[1]) - if m: - subsequent_prefix = lines[1][0:m.end()] + regex_match = space_prefix_pattern.match(lines[1]) + if regex_match: + subsequent_prefix = lines[1][0:regex_match.end()] else: subsequent_prefix = '' else: @@ -608,20 +623,20 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): initial_prefix = '' subsequent_prefix = '' - pt = paragraph_region.begin() - scope_r = self.view.extract_scope(pt) - scope_name = self.view.scope_name(pt) - if len(lines)==1 and is_quoted_string(scope_r, scope_name): + point = paragraph_region.begin() + scope_region = self.view.extract_scope(point) + scope_name = self.view.scope_name(point) + if len(lines)==1 and is_quoted_string(scope_region, scope_name): # A multi-line quoted string, that is currently only on one line. # This is mainly for Python docstrings. Not sure if it's a # problem in other cases. - true_first_line_r = self.view.line(pt) + true_first_line_r = self.view.line(point) true_first_line = self.view.substr(true_first_line_r) - if true_first_line_r.begin() <= scope_r.begin(): - m = space_prefix_pattern.match(true_first_line) + if true_first_line_r.begin() <= scope_region.begin(): + regex_match = space_prefix_pattern.match(true_first_line) debug('single line quoted string triggered') - if m: - subsequent_prefix = m.group() + subsequent_prefix + if regex_match: + subsequent_prefix = regex_match.group() + subsequent_prefix # Remove the prefixes that are there. new_lines = [] From 4f619c3beac1a8a075e422f19a3aa8472dcdc6cb Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 23 Nov 2017 15:40:52 -0200 Subject: [PATCH 041/160] Fixed comment symbol being duplicated on lines with comments --- tests/semantic_linefeed_manual_tests.py | 8 +++-- tests/semantic_linefeed_unit_tests.py | 42 +++++++++++++--------- wrap_plus.py | 47 +++++++++++++++---------- 3 files changed, 60 insertions(+), 37 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index 9bda4cd..b7aa776 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -28,14 +28,16 @@ def run_manual_tests(): wrapper.expand_tabs = False wrapper.subsequent_indent = " " - # wrap_plus._split_lines( wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50, " " ) - # wrap_plus._split_lines( wrapper, [ "This is my very long line which will wrap near its end,\n" ], 50, " " ) + # wrap_plus._split_lines( wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50 ) + # wrap_plus._split_lines( wrapper, [ "This is my very long line which will wrap near its end,\n" ], 50 ) # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,\n" ], " ", " " ) # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,", "This is my very long line which will wrap near its end," ], " ", " " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "% you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) + wrap_plus.balance_characters_between_line_wraps( wrapper, [ "% you still only configuring a few languages closely related.", "On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) wrap_plus._width = 80 - wrap_plus._split_lines( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], 80, " " ) + # wrap_plus._split_lines( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], 80 ) # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], " ", " " ) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 007b5d0..d87275b 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -9,7 +9,7 @@ wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] -def run_unit_tests(): +def run_unit_tests(unit_tests_to_run=[]): runner = unittest.TextTestRunner() classes = \ @@ -18,15 +18,18 @@ def run_unit_tests(): LineBalancingUnitTests, ] - # Comment all the tests names on this list, to run all Unit Tests - unit_tests_to_run = \ - [ - # "test_split_lines_with_trailing_new_line", - # "test_split_lines_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_with_trailing_new_line", - # "test_balance_characters_between_line_wraps_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_ending_with_long_word", - ] + if len( unit_tests_to_run ) < 1: + + # Comment all the tests names on this list, to run all Unit Tests + unit_tests_to_run = \ + [ + # "test_semantic_line_wrap_line_starting_with_comment", + # "test_split_lines_with_trailing_new_line", + # "test_split_lines_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_with_trailing_new_line", + # "test_balance_characters_between_line_wraps_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_ending_with_long_word", + ] runner.run( suite( classes, unit_tests_to_run ) ) @@ -48,21 +51,23 @@ def setUp(self): global maximum_words_in_comma_separated_list maximum_words_in_comma_separated_list = 4 + # _split_lines Unit Tests def test_split_lines_without_trailing_new_line(self): - self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,']], + self.assertEqual( [['This is my very long line\n', ' which will wrap near its\n', ' end,']], self.wrap_plus._split_lines( - self.wrapper, ["This is my very long line which will wrap near its end,"], 50, " " ) ) + self.wrapper, ["This is my very long line which will wrap near its end,"], 50 ) ) def test_split_lines_with_trailing_new_line(self): - self.assertEqual( [[' This is my very long line\n', ' which will wrap near its\n', ' end,\n']], + self.assertEqual( [['This is my very long line\n', ' which will wrap near its\n', ' end,\n']], self.wrap_plus._split_lines( - self.wrapper, ["This is my very long line which will wrap near its end,\n"], 50, " " ) ) + self.wrapper, ["This is my very long line which will wrap near its end,\n"], 50 ) ) def test_split_lines_with_very_long_line_and_word(self): - self.assertEqual( [[' This is my very long line which my\n', ' very long line which\n', ' my_very_long_line_which_will_wrap_near_its_end,']], + self.assertEqual( [['This is my very long line which my\n', ' very long line which\n', ' my_very_long_line_which_will_wrap_near_its_end,']], self.wrap_plus._split_lines( - self.wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50, " " ) ) + self.wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50 ) ) + # balance_characters_between_line_wraps Unit Tests def test_balance_characters_between_line_wraps_with_trailing_new_line(self): self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,\n'], self.wrap_plus.balance_characters_between_line_wraps( @@ -73,6 +78,11 @@ def test_balance_characters_between_line_wraps_without_trailing_new_line(self): self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, ["This is my very long line which will wrap near its end,"], " ", " " ) ) + def test_semantic_line_wrap_line_starting_with_comment(self): + self.assertEqual( ['% ', 'you still only configuring a few languages closely\n', '% related. On this case, C, C++, Java, Pawn, etc.'], + self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, + [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) ) + def test_balance_characters_between_line_wraps_ending_with_long_word(self): self.wrap_plus._width = 80 self.assertEqual( [' ', 'In this proposal last chapter which lies on the part\n', diff --git a/wrap_plus.py b/wrap_plus.py index 1f79875..3d2adf4 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -705,6 +705,7 @@ def line_wrapper_type(): if balance_characters_between_line_wraps: text = self.balance_characters_between_line_wraps( wrapper, text, initial_prefix, subsequent_prefix ) + # print( 'run, text: ' + "".join( text ) ) return "".join( text ) else: @@ -749,7 +750,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_pre wrapper.subsequent_indent = subsequent_prefix new_text = [initial_prefix] - splited_lines = self._split_lines( wrapper, text_lines, self._width, subsequent_prefix ) + splited_lines = self._split_lines( wrapper, text_lines, self._width ) for index, new_lines in enumerate( splited_lines ): lines_count = len( new_lines ) @@ -777,23 +778,20 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_pre while lines_count == first_lines_count \ and increment_percent < 2: - new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, subsequent_prefix, increment_percent )[0] + new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, increment_percent )[0] first_lines_count = len( new_lines ) increment_percent *= 1.1 new_text.extend( new_lines ) - # The first line need to be manually fixed by removing the fist indentation - new_text[1] = new_text[1].lstrip() - - # print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) + print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) return new_text - def _split_lines(self, wrapper, text_lines, maximum_line_width, subsequent_prefix, middle_of_the_line_increment_percent=1): + def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_line_increment_percent=1): """ - (input) text_lines: ['This is my very long line which will wrap near its end,\n'] - (output) new_lines: [[' This is my very long line\n', ' which will wrap near its\n', ' end,\n']] + (input) text_lines: [' This is my very long line which will wrap near its end,\n'] + (output) new_lines: [['This is my very long line\n', ' which will wrap near its\n', ' end,\n']] """ new_lines = [] @@ -811,9 +809,13 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, subsequent_prefi else: break - # print( "maximum_line_width: %d, new_width: %d (%f)" % ( maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) + print( "_split_lines, maximum_line_width: %d, new_width: %d (%f)" % ( maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) wrapper.width = math.ceil( new_line_length * middle_of_the_line_increment_percent ) + + print( "_split_lines, line: " + line ) wrapped_line = wrapper.fill( line ) + + print( "_split_lines, wrapped_line: " + wrapped_line ) wrapped_lines = wrapped_line.split( "\n" ) # Add again the removed `\n` character due the `split` statement @@ -822,16 +824,13 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, subsequent_prefi for _wrapped_line in wrapped_lines: fixed_wrapped_lines.append( _wrapped_line + "\n" ) - # The first line need to be manually fixed by adding the fist indentation - fixed_wrapped_lines[0] = subsequent_prefix + fixed_wrapped_lines[0] - # The last line need to be manually fixed by removing the trailing last time, if not existent on the original if line[-1] != "\n": fixed_wrapped_lines[-1] = fixed_wrapped_lines[-1][0:-1] new_lines.append( fixed_wrapped_lines ) - # print( "_split_lines, new_lines: " + str( new_lines ) ) + print( "_split_lines, new_lines: " + str( new_lines ) ) return new_lines def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, @@ -971,7 +970,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, if len( accumulated_line ): new_text.append(accumulated_line) - # print( "semantic_line_wrap, new_text: " + str( new_text ) ) + print( "semantic_line_wrap, new_text: " + str( new_text ) ) return new_text def peek_next_word_length(self, index, text): @@ -1145,8 +1144,20 @@ def run_tests(): from .tests import semantic_linefeed_unit_tests from .tests import semantic_linefeed_manual_tests - semantic_linefeed_unit_tests.run_unit_tests() - semantic_linefeed_manual_tests.run_manual_tests() + # Comment all the tests names on this list, to run all Unit Tests + unit_tests_to_run = \ + [ + # "test_split_lines_with_trailing_new_line", + # "test_semantic_line_wrap_line_starting_with_comment", + # "test_split_lines_with_trailing_new_line", + # "test_split_lines_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_with_trailing_new_line", + # "test_balance_characters_between_line_wraps_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_ending_with_long_word", + ] + + semantic_linefeed_unit_tests.run_unit_tests( unit_tests_to_run ) + # semantic_linefeed_manual_tests.run_manual_tests() def plugin_loaded(): @@ -1154,6 +1165,6 @@ def plugin_loaded(): Running single test from unittest.TestCase via command line https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line """ - # run_tests() pass + run_tests() From b8142ef9f377f3ac28b52b5d00b7721517059429 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 23 Nov 2017 20:30:47 -0200 Subject: [PATCH 042/160] Partially fixed line deletion with big sequential indentation. --- tests/semantic_linefeed_manual_tests.py | 10 +- tests/semantic_linefeed_unit_tests.py | 25 ++++ wrap_plus.py | 150 ++++++++++++++---------- 3 files changed, 124 insertions(+), 61 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index b7aa776..83b2e60 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -34,9 +34,17 @@ def run_manual_tests(): # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,\n" ], " ", " " ) # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "This is my very long line which will wrap near its end,", "This is my very long line which will wrap near its end," ], " ", " " ) # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "% you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) - wrap_plus.balance_characters_between_line_wraps( wrapper, [ "% you still only configuring a few languages closely related.", "On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "% you still only configuring a few languages closely related.", "On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) + + line = "This is my very long line which will wrap near its end," + wrap_plus.calculate_lines_count( line, " ", " ", 50 ) + + wrap_plus._width = 50 + wrapper.subsequent_indent = " " + # wrap_plus._split_lines( wrapper, [ " This is my very long line which will wrap near its end,\n" ], 50 ) wrap_plus._width = 80 + wrapper.subsequent_indent = " " # wrap_plus._split_lines( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], 80 ) # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "In this proposal last chapter which lies on the part called `\\nameref{sec:software_implementation}'," ], " ", " " ) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index d87275b..5a012da 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -51,7 +51,32 @@ def setUp(self): global maximum_words_in_comma_separated_list maximum_words_in_comma_separated_list = 4 + # calculate_lines_count Unit Tests + def test_calculate_lines_count_with_maximum_lines_indent(self): + line = "This is my very long line which will wrap near its end," + indentation = " " + result = self.wrap_plus.calculate_lines_count( line, indentation, indentation, 50 ) + self.assertEqual( (138, 8335), result ) + + def test_calculate_lines_count_with_minimum_lines_indent(self): + line = "This is my very long line which will wrap near its end," + indentation = "" + result = self.wrap_plus.calculate_lines_count( line, indentation, indentation, 50 ) + self.assertEqual( (2, 55), result ) + + def test_calculate_lines_count_with_only_one_line(self): + line = "This is my very long line which will wrap near its end," + indentation = "" + result = self.wrap_plus.calculate_lines_count( line, indentation, indentation, 80 ) + self.assertEqual( (1, 55), result ) + # _split_lines Unit Tests + def test_split_lines_with_long_subsequent_indentation(self): + self.wrapper.subsequent_indent = " " + self.assertEqual( [['This is my very long line which will\n', ' wrap near its\n', ' end,']], + self.wrap_plus._split_lines( + self.wrapper, ["This is my very long line which will wrap near its end,"], 50 ) ) + def test_split_lines_without_trailing_new_line(self): self.assertEqual( [['This is my very long line\n', ' which will wrap near its\n', ' end,']], self.wrap_plus._split_lines( diff --git a/wrap_plus.py b/wrap_plus.py index 3d2adf4..acb973b 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -580,20 +580,20 @@ def _make_indent(self): def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): # The comment prefix has already been stripped from the lines. # If the first line starts with a list-like thing, then that will be the initial prefix. - initial_prefix = '' - subsequent_prefix = '' + initial_indent = '' + subsequent_indent = '' first_line = lines[0] regex_match = list_pattern.match(first_line) if regex_match: - initial_prefix = first_line[0:regex_match.end()] - stripped_prefix = initial_prefix.lstrip() - leading_whitespace = initial_prefix[:len(initial_prefix)-len(stripped_prefix)] - subsequent_prefix = leading_whitespace+' '*self._width_in_spaces(stripped_prefix) + initial_indent = first_line[0:regex_match.end()] + stripped_prefix = initial_indent.lstrip() + leading_whitespace = initial_indent[:len(initial_indent)-len(stripped_prefix)] + subsequent_indent = leading_whitespace+' '*self._width_in_spaces(stripped_prefix) else: regex_match = field_pattern.match(first_line) if regex_match: # The spaces in front of the field start. - initial_prefix = regex_match.group(1) + initial_indent = regex_match.group(1) if len(lines) > 1: # How to handle subsequent lines. regex_match = space_prefix_pattern.match(lines[1]) @@ -601,27 +601,27 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): # It's already indented, keep this indent level # (unless it is less than where the field started). spaces = regex_match.group(0) - if self._width_in_spaces(spaces) >= self._width_in_spaces(initial_prefix)+1: - subsequent_prefix = spaces - if not subsequent_prefix: + if self._width_in_spaces(spaces) >= self._width_in_spaces(initial_indent)+1: + subsequent_indent = spaces + if not subsequent_indent: # Not already indented, make an indent. - subsequent_prefix = initial_prefix + self._make_indent() + subsequent_indent = initial_indent + self._make_indent() else: regex_match = space_prefix_pattern.match(first_line) if regex_match: - initial_prefix = first_line[0:regex_match.end()] + initial_indent = first_line[0:regex_match.end()] if len(lines) > 1: regex_match = space_prefix_pattern.match(lines[1]) if regex_match: - subsequent_prefix = lines[1][0:regex_match.end()] + subsequent_indent = lines[1][0:regex_match.end()] else: - subsequent_prefix = '' + subsequent_indent = '' else: - subsequent_prefix = initial_prefix + subsequent_indent = initial_indent else: # Should never happen. - initial_prefix = '' - subsequent_prefix = '' + initial_indent = '' + subsequent_indent = '' point = paragraph_region.begin() scope_region = self.view.extract_scope(point) @@ -636,20 +636,20 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): regex_match = space_prefix_pattern.match(true_first_line) debug('single line quoted string triggered') if regex_match: - subsequent_prefix = regex_match.group() + subsequent_prefix + subsequent_indent = regex_match.group() + subsequent_indent # Remove the prefixes that are there. new_lines = [] - new_lines.append(first_line[len(initial_prefix):].strip()) + new_lines.append(first_line[len(initial_indent):].strip()) for line in lines[1:]: - if line.startswith(subsequent_prefix): - line = line[len(subsequent_prefix):] + if line.startswith(subsequent_indent): + line = line[len(subsequent_indent):] new_lines.append(line.strip()) - debug('initial_prefix=%r subsequent_prefix=%r', initial_prefix, subsequent_prefix) + debug('initial_indent=%r subsequent_indent=%r', initial_indent, subsequent_indent) - return (required_comment_prefix+initial_prefix, - required_comment_prefix+subsequent_prefix, + return (required_comment_prefix+initial_indent, + required_comment_prefix+subsequent_indent, new_lines) def run(self, edit, width=0): @@ -698,12 +698,12 @@ def line_wrapper_type(): # minimum_line_size_percent = 0.0 disable_line_wrapping_by_maximum_width = True - text = self.semantic_line_wrap( paragraph_lines, initial_prefix, subsequent_prefix, + text = self.semantic_line_wrap( paragraph_lines, initial_indent, subsequent_indent, minimum_line_size_percent, disable_line_wrapping_by_maximum_width, balance_characters_between_line_wraps ) if balance_characters_between_line_wraps: - text = self.balance_characters_between_line_wraps( wrapper, text, initial_prefix, subsequent_prefix ) + text = self.balance_characters_between_line_wraps( wrapper, text, initial_indent, subsequent_indent ) # print( 'run, text: ' + "".join( text ) ) return "".join( text ) @@ -711,7 +711,7 @@ def line_wrapper_type(): else: def line_wrapper_type(): - return self.classic_wrap_text(wrapper, paragraph_lines, initial_prefix, subsequent_prefix) + return self.classic_wrap_text(wrapper, paragraph_lines, initial_indent, subsequent_indent) # print( "self._width: " + str( self._width ) ) if paragraphs: @@ -724,7 +724,7 @@ def line_wrapper_type(): # the calls to replace(). for index, selection in enumerate(self.view.sel()): paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] - initial_prefix, subsequent_prefix, paragraph_lines = self._extract_prefix(paragraph_region, paragraph_lines, required_comment_prefix) + initial_indent, subsequent_indent, paragraph_lines = self._extract_prefix(paragraph_region, paragraph_lines, required_comment_prefix) text = line_wrapper_type() @@ -741,15 +741,15 @@ def line_wrapper_type(): else: self.move_the_cursor_to_the_original_position(cursor_original_positions) - def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_prefix, subsequent_prefix): + def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_indent, subsequent_indent): """ input: ['This is my very long line which will wrap near its end,'] output: [' ', 'This is my very long line which\n ', 'will wrap near its end,'] """ - wrapper.initial_prefix = "" - wrapper.subsequent_indent = subsequent_prefix + wrapper.initial_indent = "" + wrapper.subsequent_indent = subsequent_indent - new_text = [initial_prefix] + new_text = [initial_indent] splited_lines = self._split_lines( wrapper, text_lines, self._width ) for index, new_lines in enumerate( splited_lines ): @@ -791,15 +791,17 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_pre def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_line_increment_percent=1): """ (input) text_lines: [' This is my very long line which will wrap near its end,\n'] - (output) new_lines: [['This is my very long line\n', ' which will wrap near its\n', ' end,\n']] + (output) new_lines: [[' This is my very long line\n', ' which will wrap near its\n', ' end,\n']] """ new_lines = [] + initial_indent = wrapper.initial_indent + subsequent_indent = wrapper.subsequent_indent + for line in text_lines: - line_length = len( line ) - lines_count = math.ceil( line_length / maximum_line_width ) + 1 + lines_count, line_length = self.calculate_lines_count(line, initial_indent, subsequent_indent, maximum_line_width) - for step in range( 1, lines_count ): + for step in range( 1, lines_count + 1 ): new_line_length = math.ceil( line_length / step ) # print( "new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) @@ -833,7 +835,33 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li print( "_split_lines, new_lines: " + str( new_lines ) ) return new_lines - def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, + def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum_line_width): + """ + We do not know how many lines there will be directly because when the wrap lines, + the total `line_length` is increase by the `subsequent_indent`. + """ + initial_indent_length = len( initial_indent ) + subsequent_indent_length = len( subsequent_indent ) + + lines_count = 0 + line_length = len( line ) + initial_indent_length + + new_line_length = len( line ) + initial_indent_length + last_line_length = 0 + + while last_line_length != new_line_length \ + and lines_count < line_length: + + print( "calculate_lines_count, new_line_length: " + str( new_line_length ) ) + last_line_length = new_line_length + + lines_count = math.ceil( last_line_length / maximum_line_width ) + new_line_length = ( lines_count - 1 ) * subsequent_indent_length + line_length + + print( "calculate_lines_count, lines_count: " + str( lines_count ) ) + return lines_count, new_line_length + + def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, minimum_line_size_percent=0.0, disable_line_wrapping_by_maximum_width=False, balance_characters_between_line_wraps=False): """ @@ -844,11 +872,11 @@ def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, output: [' ', 'This is my very long line which will wrap near its\n ', 'end,'] """ new_text = [] - initial_prefix_length = len( initial_prefix ) - subsequent_prefix_length = len( subsequent_prefix ) + initial_indent_length = len( initial_indent ) + subsequent_indent_length = len( subsequent_indent ) if not balance_characters_between_line_wraps: - new_text.append( initial_prefix ) + new_text.append( initial_indent ) is_allowed_to_wrap = False is_possible_space = False @@ -887,7 +915,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, if not is_flushing_accumalated_line: if not disable_line_wrapping_by_maximum_width \ - and accumulated_line_length + next_word_length + initial_prefix_length > self._width: + and accumulated_line_length + next_word_length + initial_indent_length > self._width: # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_flushing_accumalated_line = True @@ -908,7 +936,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, # print( "semantic_line_wrap, character: %s " % ( character ) ) if not disable_line_wrapping_by_maximum_width \ and not is_flushing_accumalated_line \ - and accumulated_line_length + next_word_length + initial_prefix_length > self._width: + and accumulated_line_length + next_word_length + initial_indent_length > self._width: # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_flushing_accumalated_line = True @@ -938,14 +966,14 @@ def semantic_line_wrap(self, paragraph_lines, initial_prefix, subsequent_prefix, or not is_comma_separated_list \ or is_flushing_accumalated_line: - # It is not the first line anymore, now we need to use the `subsequent_prefix_length` - initial_prefix_length = subsequent_prefix_length + # It is not the first line anymore, now we need to use the `subsequent_indent_length` + initial_indent_length = subsequent_indent_length if character in whitespace_character: character = "" accumulated_line = "".join( [accumulated_line, character, "\n", - ( "" if balance_characters_between_line_wraps else subsequent_prefix ) ] ) + ( "" if balance_characters_between_line_wraps else subsequent_indent ) ] ) # print( "semantic_line_wrap, accumulated_line flush: %s" % accumulated_line ) new_text.append( accumulated_line ) @@ -1038,39 +1066,39 @@ def is_comma_separated_list(self, text, index, line_start_index=0): return False, 0 - def classic_wrap_text(self, wrapper, paragraph_lines, initial_prefix, subsequent_prefix): - orig_initial_prefix = initial_prefix - orig_subsequent_prefix = subsequent_prefix + def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent_indent): + orig_initial_indent = initial_indent + orig_subsequent_indent = subsequent_indent - if orig_initial_prefix or orig_subsequent_prefix: + if orig_initial_indent or orig_subsequent_indent: # Textwrap is somewhat limited. It doesn't recognize tabs # in prefixes. Unfortunately, this means we can't easily # differentiate between the initial and subsequent. This # is a workaround. - initial_prefix = orig_initial_prefix.expandtabs(self._tab_width) - subsequent_prefix = orig_subsequent_prefix.expandtabs(self._tab_width) - wrapper.initial_indent = initial_prefix - wrapper.subsequent_indent = subsequent_prefix + initial_indent = orig_initial_indent.expandtabs(self._tab_width) + subsequent_indent = orig_subsequent_indent.expandtabs(self._tab_width) + wrapper.initial_indent = initial_indent + wrapper.subsequent_indent = subsequent_indent text = '\n'.join(paragraph_lines) text = text.expandtabs(self._tab_width) text = wrapper.fill(text) # Put the tabs back to the prefixes. - if orig_initial_prefix or orig_subsequent_prefix: + if orig_initial_indent or orig_subsequent_indent: - if initial_prefix != orig_subsequent_prefix or subsequent_prefix != orig_subsequent_prefix: + if initial_indent != orig_subsequent_indent or subsequent_indent != orig_subsequent_indent: lines = text.splitlines() - if initial_prefix != orig_initial_prefix: + if initial_indent != orig_initial_indent: debug('fix tabs %r', lines[0]) - lines[0] = orig_initial_prefix + lines[0][len(initial_prefix):] + lines[0] = orig_initial_indent + lines[0][len(initial_indent):] debug('new line is %r', lines[0]) - if subsequent_prefix != orig_subsequent_prefix: + if subsequent_indent != orig_subsequent_indent: for index, line in enumerate(lines[1:]): - lines[index+1] = orig_subsequent_prefix + lines[index+1][len(subsequent_prefix):] + lines[index+1] = orig_subsequent_indent + lines[index+1][len(subsequent_indent):] text = '\n'.join(lines) @@ -1147,7 +1175,9 @@ def run_tests(): # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ - # "test_split_lines_with_trailing_new_line", + # "test_split_lines_with_long_subsequent_indentation", + # "test_calculate_lines_count_with_maximum_lines_indent", + # "test_calculate_lines_count_with_minimum_lines_indent", # "test_semantic_line_wrap_line_starting_with_comment", # "test_split_lines_with_trailing_new_line", # "test_split_lines_without_trailing_new_line", From 348e2ee99ee8b0f1030340ff9ea82db0c19b4b2e Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 23 Nov 2017 21:10:17 -0200 Subject: [PATCH 043/160] Fixed erasing/cleaning/deleting the wrapped text with big indents. --- tests/semantic_linefeed_manual_tests.py | 5 ++++- tests/semantic_linefeed_unit_tests.py | 22 +++++++++++++++++++++- wrap_plus.py | 20 +++++++++----------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index 83b2e60..929ddb2 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -37,7 +37,10 @@ def run_manual_tests(): # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "% you still only configuring a few languages closely related.", "On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) line = "This is my very long line which will wrap near its end," - wrap_plus.calculate_lines_count( line, " ", " ", 50 ) + # wrap_plus.calculate_lines_count( line, " ", " ", 50 ) + + indent = " " + wrap_plus.balance_characters_between_line_wraps( wrapper, ["% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja"], "% ", indent ) wrap_plus._width = 50 wrapper.subsequent_indent = " " diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 5a012da..018cf55 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -93,6 +93,26 @@ def test_split_lines_with_very_long_line_and_word(self): self.wrapper, [ "This is my very long line which my very long line which my_very_long_line_which_will_wrap_near_its_end," ], 50 ) ) # balance_characters_between_line_wraps Unit Tests + def test_balance_characters_between_line_wraps_with_long_subsequent_indentation(self): + indent = " " + input_text = "% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja" + expected_list = \ + [ + '% ', + '% tests dd açsdkjflçk çalskdj fçlakj lçkasjd\n', + ' fçlakjs\n', + ' dçflkjadd\n', + ' açsdkjflçk\n', + ' çalskdj\n', + ' fçlakj\n', + ' lçkasjd\n', + ' fçlakjs\n', + ' dçflkja' + ] + self.assertEqual( expected_list, + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, [input_text], "% ", indent ) ) + def test_balance_characters_between_line_wraps_with_trailing_new_line(self): self.assertEqual( [' ', 'This is my very long line which\n', ' will wrap near its end,\n'], self.wrap_plus.balance_characters_between_line_wraps( @@ -103,7 +123,7 @@ def test_balance_characters_between_line_wraps_without_trailing_new_line(self): self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, ["This is my very long line which will wrap near its end,"], " ", " " ) ) - def test_semantic_line_wrap_line_starting_with_comment(self): + def test_balance_characters_between_line_wraps_starting_with_comment(self): self.assertEqual( ['% ', 'you still only configuring a few languages closely\n', '% related. On this case, C, C++, Java, Pawn, etc.'], self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) ) diff --git a/wrap_plus.py b/wrap_plus.py index acb973b..9014c1b 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -767,21 +767,18 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind if next_index < lines_count \ and len( new_line ) < math.ceil( len( new_lines_reversed[next_index] ) / 2 ): - break + increment_percent = 1.1 - else: - continue + # Try to increase the maximum width until the trailing line vanishes + while lines_count == first_lines_count \ + and increment_percent < 2: - increment_percent = 1.1 + new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, increment_percent )[0] - # Try to increase the maximum width until the trailing line vanishes - while lines_count == first_lines_count \ - and increment_percent < 2: + first_lines_count = len( new_lines ) + increment_percent *= 1.1 - new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, increment_percent )[0] - - first_lines_count = len( new_lines ) - increment_percent *= 1.1 + break new_text.extend( new_lines ) @@ -1175,6 +1172,7 @@ def run_tests(): # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ + # "test_balance_characters_between_line_wraps_with_long_subsequent_indentation", # "test_split_lines_with_long_subsequent_indentation", # "test_calculate_lines_count_with_maximum_lines_indent", # "test_calculate_lines_count_with_minimum_lines_indent", From 395c5428f436482f1736f6f8af05db547eead114 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 23 Nov 2017 23:29:28 -0200 Subject: [PATCH 044/160] Fixed balance_characters_between_line_wraps with long indentations on the subsequent lines. --- tests/semantic_linefeed_manual_tests.py | 5 +++- tests/semantic_linefeed_unit_tests.py | 34 +++++++++++++++++-------- wrap_plus.py | 7 +++-- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index 929ddb2..13f9d50 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -40,9 +40,12 @@ def run_manual_tests(): # wrap_plus.calculate_lines_count( line, " ", " ", 50 ) indent = " " + # wrap_plus.balance_characters_between_line_wraps( wrapper, ["% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja"], "% ", indent ) + + wrapper.width = 80 + wrap_plus._width = 80 wrap_plus.balance_characters_between_line_wraps( wrapper, ["% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja"], "% ", indent ) - wrap_plus._width = 50 wrapper.subsequent_indent = " " # wrap_plus._split_lines( wrapper, [ " This is my very long line which will wrap near its end,\n" ], 50 ) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 018cf55..5b98ffc 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -94,20 +94,34 @@ def test_split_lines_with_very_long_line_and_word(self): # balance_characters_between_line_wraps Unit Tests def test_balance_characters_between_line_wraps_with_long_subsequent_indentation(self): - indent = " " + indent = "% " input_text = "% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja" expected_list = \ [ - '% ', + '', '% tests dd açsdkjflçk çalskdj fçlakj lçkasjd\n', - ' fçlakjs\n', - ' dçflkjadd\n', - ' açsdkjflçk\n', - ' çalskdj\n', - ' fçlakj\n', - ' lçkasjd\n', - ' fçlakjs\n', - ' dçflkja' + '% fçlakjs\n', + '% dçflkjadd\n', + '% açsdkjflçk\n', + '% çalskdj\n', + '% fçlakj\n', + '% lçkasjd\n', + '% fçlakjs\n', + '% dçflkja' + ] + self.assertEqual( expected_list, + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, [input_text], "", indent ) ) + + def test_balance_characters_between_line_wraps_with_long_indentation_balance(self): + indent = "% " + self.wrapper.width = 80 + self.wrap_plus._width = 80 + input_text = "% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja" + expected_list = \ + [ + '% ', '% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj\n', + '% fçlakj lçkasjd fçlakjs dçflkja' ] self.assertEqual( expected_list, self.wrap_plus.balance_characters_between_line_wraps( diff --git a/wrap_plus.py b/wrap_plus.py index 9014c1b..5bef973 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -748,6 +748,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind """ wrapper.initial_indent = "" wrapper.subsequent_indent = subsequent_indent + subsequent_indent_length = len( subsequent_indent ) new_text = [initial_indent] splited_lines = self._split_lines( wrapper, text_lines, self._width ) @@ -765,7 +766,8 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind next_index = _index + 1 if next_index < lines_count \ - and len( new_line ) < math.ceil( len( new_lines_reversed[next_index] ) / 2 ): + and len( new_line ) - subsequent_indent_length \ + < math.ceil( ( len( new_lines_reversed[next_index] ) - subsequent_indent_length ) / 2 ): increment_percent = 1.1 @@ -1172,6 +1174,7 @@ def run_tests(): # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ + # "test_balance_characters_between_line_wraps_with_long_indentation_balance", # "test_balance_characters_between_line_wraps_with_long_subsequent_indentation", # "test_split_lines_with_long_subsequent_indentation", # "test_calculate_lines_count_with_maximum_lines_indent", @@ -1185,7 +1188,7 @@ def run_tests(): ] semantic_linefeed_unit_tests.run_unit_tests( unit_tests_to_run ) - # semantic_linefeed_manual_tests.run_manual_tests() + #semantic_linefeed_manual_tests.run_manual_tests() def plugin_loaded(): From c100b7f4c3b35c8e801833dd001b7f1742af375a Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 24 Nov 2017 00:20:47 -0200 Subject: [PATCH 045/160] Fixed balance_characters_between_line_wraps not inserting comment signs/subsequent indentations. --- tests/semantic_linefeed_manual_tests.py | 4 +++- tests/semantic_linefeed_unit_tests.py | 24 +++++++++++++++++++++++- wrap_plus.py | 15 +++++++++++---- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index 13f9d50..bba284d 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -13,6 +13,7 @@ def run_manual_tests(): wrap_plus = wrap_plus_module.WrapLinesPlusCommand( None ) wrap_plus._width = 80 + # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "% ", "% ", balance_characters_between_line_wraps=True ) # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "", balance_characters_between_line_wraps=True ) # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) # wrap_plus.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "", "" ) @@ -44,7 +45,8 @@ def run_manual_tests(): wrapper.width = 80 wrap_plus._width = 80 - wrap_plus.balance_characters_between_line_wraps( wrapper, ["% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja"], "% ", indent ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, ["% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja"], "% ", indent ) + wrap_plus.balance_characters_between_line_wraps( wrapper, [ "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", "Ela eh uma heurística,", "que cada bloco implementa e faz ele gerar um arquivo de" ], "% ", "% " ) wrapper.subsequent_indent = " " # wrap_plus._split_lines( wrapper, [ " This is my very long line which will wrap near its end,\n" ], 50 ) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 5b98ffc..01819a5 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -113,7 +113,29 @@ def test_balance_characters_between_line_wraps_with_long_subsequent_indentation( self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, [input_text], "", indent ) ) - def test_balance_characters_between_line_wraps_with_long_indentation_balance(self): + def test_balance_characters_between_line_wraps_withd_comment_indentation_balance(self): + self.wrapper.width = 80 + self.wrap_plus._width = 80 + input_text = \ + [ + "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", + "Ela eh uma heurística,", + "que cada bloco implementa e faz ele gerar um arquivo de" + ] + expected_list = \ + [ + '% ', + 'Inclui a IA para reconhecer o formatação nos módulos de beautifying.', + '% ', + 'Ela eh uma heurística,', + '% ', + 'que cada bloco implementa e faz ele gerar um arquivo de', + ] + self.assertEqual( expected_list, + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, input_text, "% ", "% " ) ) + + def test_balance_characters_between_line_wraps_commented_line(self): indent = "% " self.wrapper.width = 80 self.wrap_plus._width = 80 diff --git a/wrap_plus.py b/wrap_plus.py index 5bef973..7432e9c 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -750,7 +750,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind wrapper.subsequent_indent = subsequent_indent subsequent_indent_length = len( subsequent_indent ) - new_text = [initial_indent] + new_text = [] splited_lines = self._split_lines( wrapper, text_lines, self._width ) for index, new_lines in enumerate( splited_lines ): @@ -759,7 +759,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind # When there are more than 2 lines, we can get a situation like this: # new_lines: [' This is my very long line\n which will wrap near its\n end,'] - if lines_count > 2: + if lines_count > 1: new_lines_reversed = list( reversed( new_lines ) ) for _index, new_line in enumerate( new_lines_reversed ): @@ -782,7 +782,13 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind break - new_text.extend( new_lines ) + if index < 1: + new_text.append( initial_indent ) + new_text.extend( new_lines ) + + else: + new_text.append( subsequent_indent ) + new_text.extend( new_lines ) print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) return new_text @@ -1174,6 +1180,7 @@ def run_tests(): # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ + # "", # "test_balance_characters_between_line_wraps_with_long_indentation_balance", # "test_balance_characters_between_line_wraps_with_long_subsequent_indentation", # "test_split_lines_with_long_subsequent_indentation", @@ -1188,7 +1195,7 @@ def run_tests(): ] semantic_linefeed_unit_tests.run_unit_tests( unit_tests_to_run ) - #semantic_linefeed_manual_tests.run_manual_tests() + # semantic_linefeed_manual_tests.run_manual_tests() def plugin_loaded(): From a12b62b996181a0c57e1fef5fc173676f4bd4faf Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 24 Nov 2017 02:25:17 -0200 Subject: [PATCH 046/160] Created big multiline balancing support with smoother algorithms. --- tests/semantic_linefeed_manual_tests.py | 4 +- tests/semantic_linefeed_unit_tests.py | 29 +++++++++++- wrap_plus.py | 59 ++++++++++++++++++++----- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index bba284d..c35fdb4 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -43,10 +43,10 @@ def run_manual_tests(): indent = " " # wrap_plus.balance_characters_between_line_wraps( wrapper, ["% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja"], "% ", indent ) - wrapper.width = 80 wrap_plus._width = 80 # wrap_plus.balance_characters_between_line_wraps( wrapper, ["% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja"], "% ", indent ) - wrap_plus.balance_characters_between_line_wraps( wrapper, [ "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", "Ela eh uma heurística,", "que cada bloco implementa e faz ele gerar um arquivo de" ], "% ", "% " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", "Ela eh uma heurística,", "que cada bloco implementa e faz ele gerar um arquivo de" ], "% ", "% " ) + wrap_plus.balance_characters_between_line_wraps( wrapper, [ "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", "Ela eh uma heurística,", "que cada bloco implementa e faz ele gerar um arquivo de configuração que representa a atual formatação do código (aqui esta o verdadeiro desafio do trabalho,", "pesquise trabalhos correlatos).", ], "% ", "% " ) wrapper.subsequent_indent = " " # wrap_plus._split_lines( wrapper, [ " This is my very long line which will wrap near its end,\n" ], 50 ) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 01819a5..506758d 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -113,7 +113,34 @@ def test_balance_characters_between_line_wraps_with_long_subsequent_indentation( self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, [input_text], "", indent ) ) - def test_balance_characters_between_line_wraps_withd_comment_indentation_balance(self): + def test_balance_characters_between_line_wraps_with_big_multi_line_balancing(self): + self.wrapper.width = 80 + self.wrap_plus._width = 80 + input_text = \ + [ + "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", + "Ela eh uma heurística,", + "que cada bloco implementa e faz ele gerar um arquivo de configuração que representa a atual formatação do código (aqui esta o verdadeiro desafio do trabalho,", + "pesquise trabalhos correlatos).", + ] + expected_list = \ + [ + '% ', + 'Inclui a IA para reconhecer o formatação nos módulos de beautifying.', + '% ', + 'Ela eh uma heurística,', + '% ', + 'que cada bloco implementa e faz ele gerar um arquivo de\n', + '% configuração que representa a atual formatação do código\n', + '% (aqui esta o verdadeiro desafio do trabalho,', + '% ', + 'pesquise trabalhos correlatos).', + ] + self.assertEqual( expected_list, + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, input_text, "% ", "% " ) ) + + def test_balance_characters_between_line_wraps_with_comment_indentation_balance(self): self.wrapper.width = 80 self.wrap_plus._width = 80 input_text = \ diff --git a/wrap_plus.py b/wrap_plus.py index 7432e9c..8ac1231 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -746,22 +746,29 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind input: ['This is my very long line which will wrap near its end,'] output: [' ', 'This is my very long line which\n ', 'will wrap near its end,'] """ + wrapper.width = self._width wrapper.initial_indent = "" wrapper.subsequent_indent = subsequent_indent subsequent_indent_length = len( subsequent_indent ) - new_text = [] - splited_lines = self._split_lines( wrapper, text_lines, self._width ) + # `decrement_percent` must be stronger than 1.1, i.e., 1.1*1.1 = 1.21*0.9 = 1.089 < 1.1 + # otherwise this could immediately fail as the last line length would already be + # greater than `self._width / 2` + INCREMENT_VALUE = 1.05 + DECREMENT_VALUE = 0.95 + + new_text = [] + splited_lines = self._split_lines( wrapper, text_lines, self._width ) for index, new_lines in enumerate( splited_lines ): - lines_count = len( new_lines ) - first_lines_count = lines_count + lines_count = len( new_lines ) - # When there are more than 2 lines, we can get a situation like this: - # new_lines: [' This is my very long line\n which will wrap near its\n end,'] if lines_count > 1: + increment_percent = INCREMENT_VALUE new_lines_reversed = list( reversed( new_lines ) ) + # When there are more than 1 lines, we can get a situation like this: + # new_lines: [' This is my very long line\n which will wrap near its\n end,'] for _index, new_line in enumerate( new_lines_reversed ): next_index = _index + 1 @@ -769,7 +776,8 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind and len( new_line ) - subsequent_indent_length \ < math.ceil( ( len( new_lines_reversed[next_index] ) - subsequent_indent_length ) / 2 ): - increment_percent = 1.1 + increment_percent = INCREMENT_VALUE + first_lines_count = lines_count # Try to increase the maximum width until the trailing line vanishes while lines_count == first_lines_count \ @@ -778,10 +786,24 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, increment_percent )[0] first_lines_count = len( new_lines ) - increment_percent *= 1.1 + increment_percent *= INCREMENT_VALUE break + print( "Shrinking the lines..." ) + if self.is_there_line_over_the_wrap_limit( new_lines ): + + decrement_percent = increment_percent * DECREMENT_VALUE + new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, decrement_percent )[0] + + # Try to decrease the maximum width until create a trailing new line + while ( self.is_there_line_over_the_wrap_limit(new_lines) \ + or self.is_line_bellow_half_wrap_limit( new_lines, subsequent_indent_length ) ) \ + and decrement_percent > 0.4: + + decrement_percent *= DECREMENT_VALUE + new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, decrement_percent )[0] + if index < 1: new_text.append( initial_indent ) new_text.extend( new_lines ) @@ -793,6 +815,23 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) return new_text + def is_line_bellow_half_wrap_limit(self, new_lines, subsequent_indent_length): + return len( new_lines[-1] ) - subsequent_indent_length \ + < math.floor( ( self._width - subsequent_indent_length ) / 1.8 ) + + def is_there_line_over_the_wrap_limit(self, new_lines): + """ + We need to check whether some line has passed over the wrap limit. This can happen + when a line with width 160 can be split in 2 lines of width 80, but not all the + words fit on the first line with 80 characters exactly. + """ + for new_line in new_lines: + + if len( new_line ) > self._width: + return True + + return False + def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_line_increment_percent=1): """ (input) text_lines: [' This is my very long line which will wrap near its end,\n'] @@ -808,7 +847,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li for step in range( 1, lines_count + 1 ): new_line_length = math.ceil( line_length / step ) - # print( "new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) + print( "_split_lines, new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) if new_line_length > maximum_line_width: continue @@ -1180,7 +1219,7 @@ def run_tests(): # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ - # "", + # "test_balance_characters_between_line_wraps_with_big_multi_line_balancing", # "test_balance_characters_between_line_wraps_with_long_indentation_balance", # "test_balance_characters_between_line_wraps_with_long_subsequent_indentation", # "test_split_lines_with_long_subsequent_indentation", From 808412de1ae57d5bd652178b258790a19c8eb12a Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 24 Nov 2017 15:16:38 -0200 Subject: [PATCH 047/160] Fixed line wrapping when there are lines over the limit and some line has some very big word or some very big indentation, then there is nothing we can do other than discard the results. --- tests/semantic_linefeed_unit_tests.py | 12 +++++------ wrap_plus.py | 30 ++++++++++++++++++--------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 506758d..8bebe1e 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -114,7 +114,6 @@ def test_balance_characters_between_line_wraps_with_long_subsequent_indentation( self.wrapper, [input_text], "", indent ) ) def test_balance_characters_between_line_wraps_with_big_multi_line_balancing(self): - self.wrapper.width = 80 self.wrap_plus._width = 80 input_text = \ [ @@ -141,13 +140,12 @@ def test_balance_characters_between_line_wraps_with_big_multi_line_balancing(sel self.wrapper, input_text, "% ", "% " ) ) def test_balance_characters_between_line_wraps_with_comment_indentation_balance(self): - self.wrapper.width = 80 self.wrap_plus._width = 80 input_text = \ [ "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", "Ela eh uma heurística,", - "que cada bloco implementa e faz ele gerar um arquivo de" + "que cada bloco implementa e faz ele gerar um arquivo de", ] expected_list = \ [ @@ -164,13 +162,13 @@ def test_balance_characters_between_line_wraps_with_comment_indentation_balance( def test_balance_characters_between_line_wraps_commented_line(self): indent = "% " - self.wrapper.width = 80 self.wrap_plus._width = 80 input_text = "% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja" expected_list = \ [ - '% ', '% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj\n', - '% fçlakj lçkasjd fçlakjs dçflkja' + '% ', '% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd\n', + '% açsdkjflçk çalskdj fçlakj\n', + '% lçkasjd fçlakjs dçflkja', ] self.assertEqual( expected_list, self.wrap_plus.balance_characters_between_line_wraps( @@ -187,7 +185,7 @@ def test_balance_characters_between_line_wraps_without_trailing_new_line(self): self.wrapper, ["This is my very long line which will wrap near its end,"], " ", " " ) ) def test_balance_characters_between_line_wraps_starting_with_comment(self): - self.assertEqual( ['% ', 'you still only configuring a few languages closely\n', '% related. On this case, C, C++, Java, Pawn, etc.'], + self.assertEqual( ['% ', 'you still only configuring a few\n', '% languages closely related. On this\n', '% case, C, C++, Java, Pawn, etc.'], self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "% ", "% " ) ) diff --git a/wrap_plus.py b/wrap_plus.py index 8ac1231..9daccc3 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -790,7 +790,9 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind break - print( "Shrinking the lines..." ) + # print( "\nShrinking the lines..." ) + new_lines_backup = list( new_lines ) + if self.is_there_line_over_the_wrap_limit( new_lines ): decrement_percent = increment_percent * DECREMENT_VALUE @@ -804,6 +806,12 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind decrement_percent *= DECREMENT_VALUE new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, decrement_percent )[0] + # If still there are lines over the limit, it means some line has some very big word + # or some very big indentation, then there is nothing we can do other than discard + # the results. Comment this out, and you will see the Unit Tests failing with it. + if self.is_there_line_over_the_wrap_limit( new_lines ): + new_lines = new_lines_backup + if index < 1: new_text.append( initial_indent ) new_text.extend( new_lines ) @@ -812,7 +820,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind new_text.append( subsequent_indent ) new_text.extend( new_lines ) - print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) + # print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) return new_text def is_line_bellow_half_wrap_limit(self, new_lines, subsequent_indent_length): @@ -847,7 +855,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li for step in range( 1, lines_count + 1 ): new_line_length = math.ceil( line_length / step ) - print( "_split_lines, new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) + # print( "_split_lines, new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) if new_line_length > maximum_line_width: continue @@ -855,13 +863,13 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li else: break - print( "_split_lines, maximum_line_width: %d, new_width: %d (%f)" % ( maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) + # print( "_split_lines, maximum_line_width: %d, new_width: %d (%f)" % ( maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) wrapper.width = math.ceil( new_line_length * middle_of_the_line_increment_percent ) - print( "_split_lines, line: " + line ) + # print( "_split_lines, line: " + line ) wrapped_line = wrapper.fill( line ) - print( "_split_lines, wrapped_line: " + wrapped_line ) + # print( "_split_lines, wrapped_line: " + wrapped_line ) wrapped_lines = wrapped_line.split( "\n" ) # Add again the removed `\n` character due the `split` statement @@ -876,7 +884,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li new_lines.append( fixed_wrapped_lines ) - print( "_split_lines, new_lines: " + str( new_lines ) ) + # print( "_split_lines, new_lines: " + str( new_lines ) ) return new_lines def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum_line_width): @@ -896,13 +904,13 @@ def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum while last_line_length != new_line_length \ and lines_count < line_length: - print( "calculate_lines_count, new_line_length: " + str( new_line_length ) ) + # print( "calculate_lines_count, new_line_length: " + str( new_line_length ) ) last_line_length = new_line_length lines_count = math.ceil( last_line_length / maximum_line_width ) new_line_length = ( lines_count - 1 ) * subsequent_indent_length + line_length - print( "calculate_lines_count, lines_count: " + str( lines_count ) ) + # print( "calculate_lines_count, lines_count: " + str( lines_count ) ) return lines_count, new_line_length def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, @@ -1042,7 +1050,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, if len( accumulated_line ): new_text.append(accumulated_line) - print( "semantic_line_wrap, new_text: " + str( new_text ) ) + # print( "semantic_line_wrap, new_text: " + str( new_text ) ) return new_text def peek_next_word_length(self, index, text): @@ -1219,6 +1227,8 @@ def run_tests(): # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ + # "test_balance_characters_between_line_wraps_commented_line", + # "test_balance_characters_between_line_wraps_starting_with_comment", # "test_balance_characters_between_line_wraps_with_big_multi_line_balancing", # "test_balance_characters_between_line_wraps_with_long_indentation_balance", # "test_balance_characters_between_line_wraps_with_long_subsequent_indentation", From 06feb5abe833839656a01e6ede153e1e80fd4a8c Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 25 Nov 2017 11:25:45 -0200 Subject: [PATCH 048/160] Reimplemented the command separated list search with O(n) function --- tests/semantic_linefeed_manual_tests.py | 9 +- tests/semantic_linefeed_unit_tests.py | 63 +++++++---- wrap_plus.py | 137 ++++++++++++++---------- 3 files changed, 131 insertions(+), 78 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index c35fdb4..823a45e 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -13,6 +13,13 @@ def run_manual_tests(): wrap_plus = wrap_plus_module.WrapLinesPlusCommand( None ) wrap_plus._width = 80 + # print( str( wrap_plus.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4 ) ) + " 1_ 2, 3_ 4_ 5" ) + # print( str( wrap_plus.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3 ) ) + " 1 2, 3 4_5 6, 7" ) + print( str( wrap_plus.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1 ) ) + " 1, 2_ 3_ 4_ 5" ) + # print( str( wrap_plus.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3 ) ) + " 1 2, 3 4_5 6, 7" ) + # print( str( "".join( wrap_plus.semantic_line_wrap( [ "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1" ], "% ", "% ", balance_characters_between_line_wraps=True ) ) ) ) + # print( "\n1 2 3 4.\n5 6 7, 1, 2, 3, 4, 5.\n6 7 8 9 1" ) + # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "% ", "% ", balance_characters_between_line_wraps=True ) # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "", balance_characters_between_line_wraps=True ) # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "" ) @@ -46,7 +53,7 @@ def run_manual_tests(): wrap_plus._width = 80 # wrap_plus.balance_characters_between_line_wraps( wrapper, ["% tests dd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkjadd açsdkjflçk çalskdj fçlakj lçkasjd fçlakjs dçflkja"], "% ", indent ) # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", "Ela eh uma heurística,", "que cada bloco implementa e faz ele gerar um arquivo de" ], "% ", "% " ) - wrap_plus.balance_characters_between_line_wraps( wrapper, [ "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", "Ela eh uma heurística,", "que cada bloco implementa e faz ele gerar um arquivo de configuração que representa a atual formatação do código (aqui esta o verdadeiro desafio do trabalho,", "pesquise trabalhos correlatos).", ], "% ", "% " ) + # wrap_plus.balance_characters_between_line_wraps( wrapper, [ "Inclui a IA para reconhecer o formatação nos módulos de beautifying.", "Ela eh uma heurística,", "que cada bloco implementa e faz ele gerar um arquivo de configuração que representa a atual formatação do código (aqui esta o verdadeiro desafio do trabalho,", "pesquise trabalhos correlatos).", ], "% ", "% " ) wrapper.subsequent_indent = " " # wrap_plus._split_lines( wrapper, [ " This is my very long line which will wrap near its end,\n" ], 50 ) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 8bebe1e..ce02356 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -209,33 +209,56 @@ def setUp(self): global maximum_words_in_comma_separated_list maximum_words_in_comma_separated_list = 4 - def test_is_command_separated_list(self): - self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, True ) - self.is_comma_separated_list( "1_ 2, 3, 4_ 5", 4, True ) - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4, True ) - self.is_comma_separated_list( "1_ 2, 3_ 4, 5", 4, True ) - - def test_is_command_separated_list_upperbound(self): - self.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1, False ) - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6, 7", 4, False ) - self.is_comma_separated_list( "1_ 2, 3_ 4__5 6_ 7", 4, False ) - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6_ 7", 4, False ) - - def test_is_command_separated_list_lowerbound(self): - self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3, True ) - self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 3, True ) - self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 3, True ) + def test_is_command_separated_list_5_items(self): + self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, (True, 12) ) + + def test_is_command_separated_list_4_items(self): + self.is_comma_separated_list( "1, 2_ 3, 4, 5", 1, (True, 12) ) + + def test_is_command_separated_list_3_items(self): + self.is_comma_separated_list( "1_ 2, 3, 4_ 5", 4, (True, 12) ) + + def test_is_command_separated_list_2_items(self): + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4, (True, 12) ) + + def test_is_command_separated_list_upperbound_with_1_by_5_trailing_items(self): + self.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1, (False, 0) ) + + def test_is_command_separated_list_upperbound_with_4_middle_items(self): + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6, 7", 4, (False, 0) ) + + def test_is_command_separated_list_upperbound_with_2_by_5_trailing_items(self): + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6_ 7", 4, (False, 0) ) + + def test_is_command_separated_list_upperbound_2_by_4_trailing_items(self): + self.is_comma_separated_list( "1_ 2, 3_ 4__5 6_ 7", 4, (False, 0) ) + + def test_is_command_separated_list_lowerbound_with_3_items(self): + self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3, (True, 14) ) + + def test_is_command_separated_list_lowerbound_with_2_items(self): + self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 3, (True, 14) ) + + def test_is_command_separated_list_lowerbound_with_1_items(self): + self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 3, (True, 14) ) + + def test_is_command_separated_list_lowerbound_with_trailing_1_space(self): + self.is_comma_separated_list( "1 2, 3_ 4_5_6 7 ", 3, (True, 15) ) + + def test_is_command_separated_list_lowerbound_with_trailing_2_space(self): + self.is_comma_separated_list( "1 2, 3_ 4_5_6 7 ", 3, (True, 16) ) def is_comma_separated_list(self, text, index, goal): self.assertTrue( text[index] in wrap_plus_module.word_separator_characters ) - self.assertEqual( goal, self.wrap_plus.is_comma_separated_list( text, index, True )[0] - or self.wrap_plus.is_comma_separated_list( text, index, False )[0] ) - - def test_semantic_line_wrap_simple_sentences(self): + self.assertEqual( goal, self.wrap_plus.is_comma_separated_list( text, index ) ) + def test_semantic_line_wrap_simple_sentence(self): self.semantic_line_wrap( "1", "1" ) + + def test_semantic_line_wrap_simple_sentence_with_single_comma(self): self.semantic_line_wrap( "which will take, you quite some time", "which will take,\nyou quite some time" ) + def test_semantic_line_wrap_simple_sentence_with_dual_comma(self): self.semantic_line_wrap( "which will take, you, quite some time", "which will take,\nyou, quite some time" ) diff --git a/wrap_plus.py b/wrap_plus.py index 9daccc3..8f2abc1 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -230,9 +230,7 @@ def CONCAT(*args): blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') maximum_words_in_comma_separated_list = 4 -list_of_words_pattern = re.compile(r'(?:^|\s)+[^ ]+', re.MULTILINE) next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) - whitespace_character = (" ", "\t") word_separator_characters = ( ",", ".", "?", "!", ":", ";" ) @@ -924,6 +922,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, output: [' ', 'This is my very long line which will wrap near its\n ', 'end,'] """ new_text = [] + initial_indent_length = len( initial_indent ) subsequent_indent_length = len( subsequent_indent ) @@ -942,9 +941,21 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, minimum_line_size = int( self._width * minimum_line_size_percent ) # print( "minimum_line_size: %s" % ( minimum_line_size ) ) + indent_length = initial_indent_length accumulated_line = "" line_start_index = 0 - comma_list_end_point = 0 + comma_list_size = 0 + last_comma_list_size = 0 + + def force_flush_accumulated_line(): + nonlocal index + nonlocal is_flushing_accumalated_line + + # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) + is_flushing_accumalated_line = True + + # Current character is a whitespace, but it must the the next, so fix the index + index -= 1 for index, character in enumerate( text ): accumulated_line_length = len( accumulated_line ) @@ -957,17 +968,18 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, is_possible_space = False # Skip the next characters as we already know they are a list. This is only called when - # the `comma_list_end_point` is lower than the `self._width`, otherwise the line will + # the `comma_list_size` is lower than the `self._width`, otherwise the line will # be immediately flushed - if comma_list_end_point > 0: - comma_list_end_point -= 1 + if comma_list_size > 0: + last_comma_list_size = comma_list_size + comma_list_size -= 1 - # print( "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, line_remaining_size: %s, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, index - line_start_index, self._width - index - line_start_index, comma_list_end_point, character ) ) + # print( "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, comma_list_end_point, character ) ) if not is_flushing_accumalated_line: if not disable_line_wrapping_by_maximum_width \ - and accumulated_line_length + next_word_length + initial_indent_length > self._width: + and accumulated_line_length + next_word_length + indent_length > self._width: # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_flushing_accumalated_line = True @@ -985,16 +997,16 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, is_flushing_comma_list = False is_comma_separated_list = False - # print( "semantic_line_wrap, character: %s " % ( character ) ) + if last_comma_list_size == 1: + last_comma_list_size = 0 + force_flush_accumulated_line() + + # print( "semantic_line_wrap, index: %d, character: %s " % ( index, character ) ) if not disable_line_wrapping_by_maximum_width \ and not is_flushing_accumalated_line \ - and accumulated_line_length + next_word_length + initial_indent_length > self._width: - - # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) - is_flushing_accumalated_line = True + and accumulated_line_length + next_word_length + indent_length > self._width: - # Current character is a whitespace, but it must the the next, so fix the index - index -= 1 + force_flush_accumulated_line() if accumulated_line_length > minimum_line_size: is_allowed_to_wrap = True @@ -1010,16 +1022,17 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, if character in word_separator_characters \ and not is_flushing_comma_list: - is_comma_separated_list, comma_list_end_point = self.is_comma_separated_list(text, index, line_start_index) - comma_list_end_point -= index - line_start_index + 3 + is_comma_separated_list, comma_list_end_point = self.is_comma_separated_list( text, index ) + comma_list_size = comma_list_end_point - ( index + 1 ) - if ( comma_list_end_point > 0 \ + # print( "semantic_line_wrap, index: %d, comma_list_size: %d" % ( index, comma_list_size ) ) + if ( comma_list_size > 0 \ and not is_flushing_comma_list ) \ or not is_comma_separated_list \ or is_flushing_accumalated_line: # It is not the first line anymore, now we need to use the `subsequent_indent_length` - initial_indent_length = subsequent_indent_length + indent_length = subsequent_indent_length if character in whitespace_character: character = "" @@ -1027,7 +1040,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, accumulated_line = "".join( [accumulated_line, character, "\n", ( "" if balance_characters_between_line_wraps else subsequent_indent ) ] ) - # print( "semantic_line_wrap, accumulated_line flush: %s" % accumulated_line ) + # print( "semantic_line_wrap, accumulated_line flush: %r" % accumulated_line ) new_text.append( accumulated_line ) accumulated_line = "" @@ -1064,58 +1077,53 @@ def peek_next_word_length(self, index, text): return 0 - def is_comma_separated_list(self, text, index, line_start_index=0): - # print( "is_comma_separated_list, index: %3d, line_start_index: %d" % ( index, line_start_index ) ) + def is_comma_separated_list(self, text, index): + """ + return if the next characters form a command separated list + return 0 if False, otherwise the `text` index where the command separated list ended + """ + # print( "is_comma_separated_list, index: %d" % ( index ) ) + comma_list_end_point = -1 - next_character = " " - text_length = len( text ) - 1 - slice_start_index = index + text_length = len( text ) - 1 + words_counter = 0 while index < text_length: index = index + 1 character = text[index] - if index + 1 < text_length: - next_character = text[index+1] - - # print( "is_comma_separated_list, character: %s, next_character: %s" % ( character, next_character ) ) - if ( character in word_separator_characters \ - and next_character in whitespace_character ) \ - or index >= text_length: - - comma_section = text[ slice_start_index+1:index+1 ] - # print( "is_comma_separated_list, text: " + comma_section ) + is_character_whitespace = character in whitespace_character - results = list_of_words_pattern.findall( comma_section ) - results_count = len( results ) - # print( "is_comma_separated_list, results: " + str( results ) ) - - if 0 < results_count < maximum_words_in_comma_separated_list: + if index < text_length: + next_character = text[index+1] + is_word_separator_character = character in word_separator_characters + is_next_character_whitepace = next_character in whitespace_character - # Get the last match object - for match in list_of_words_pattern.finditer( comma_section ): - pass + else: + next_character = '$' + is_word_separator_character = True + is_next_character_whitepace = True - match_end = match.end(0) - possible_match_end = 0 + # We count a word before it begins and set `comma_list_end_point` when we find a space after a comma + if is_character_whitespace and not is_next_character_whitepace: + words_counter += 1 - # `line_start_index` always greater than `index`, like 50 - 20 = 30 - # 50, 20 = 30, 80 - 30 = 50, 50 - 10 = 40 - # print( "is_comma_separated_list, line_remaining_size: " + str( self._width - ( index - line_start_index ) - match_end ) ) - # print( "is_comma_separated_list, match_end: " + str( match_end ) ) + # print( "is_comma_separated_list, index: %d, words_counter: %d, character: %s, next_character: %s" % ( index, words_counter, character, next_character ) ) + if is_word_separator_character and is_next_character_whitepace: - is_there_new_commas, possible_match_end = self.is_comma_separated_list( text, index, line_start_index + match_end ) - # print( "is_comma_separated_list, possible_match_end: " + str( possible_match_end ) ) + if 0 < words_counter < maximum_words_in_comma_separated_list: + comma_list_end_point = index - if possible_match_end > 0: - return True, possible_match_end + match_end + else: + break - # print( "is_comma_separated_list, slice_start_index - line_start_index + match_end: " + str( slice_start_index - line_start_index + match_end ) ) - return True, slice_start_index - line_start_index + match_end + words_counter = 0 - else: - return False, 0 + if comma_list_end_point > -1: + # print( "is_comma_separated_list (True), comma_list_end_point: %d" % ( comma_list_end_point ) ) + return True, comma_list_end_point + # print( "is_comma_separated_list (False), comma_list_end_point: %d" % ( 0 ) ) return False, 0 def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent_indent): @@ -1227,6 +1235,21 @@ def run_tests(): # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ + # "test_is_command_separated_list_5_items", + # "test_is_command_separated_list_4_items", + # "test_is_command_separated_list_3_items", + # "test_is_command_separated_list_2_items", + # "test_is_command_separated_list_upperbound_with_1_by_5_trailing_items", + # "test_is_command_separated_list_upperbound_with_4_middle_items", + # "test_is_command_separated_list_upperbound_with_2_by_5_trailing_items", + # "test_is_command_separated_list_upperbound_2_by_4_trailing_items", + # "test_is_command_separated_list_lowerbound_with_3_items", + # "test_is_command_separated_list_lowerbound_with_2_items", + # "test_is_command_separated_list_lowerbound_with_1_items", + # "test_is_command_separated_list_lowerbound_with_trailing_1_space", + # "test_semantic_line_wrap_simple_sentence_with_dual_comma", + # "test_semantic_line_wrap_with_initial_indentation", + # "test_semantic_line_wrap_with_numeric_comma_list_on_the_end", # "test_balance_characters_between_line_wraps_commented_line", # "test_balance_characters_between_line_wraps_starting_with_comment", # "test_balance_characters_between_line_wraps_with_big_multi_line_balancing", From 15a07fb30ae307abac12796d1986e6e676ed0c9d Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 25 Nov 2017 14:58:46 -0200 Subject: [PATCH 049/160] Implemented command separated list items counting. --- tests/semantic_linefeed_manual_tests.py | 6 ++-- tests/semantic_linefeed_unit_tests.py | 36 ++++++++++++------- wrap_plus.py | 47 +++++++++++++++---------- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index 823a45e..5ba18eb 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -15,10 +15,12 @@ def run_manual_tests(): # print( str( wrap_plus.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4 ) ) + " 1_ 2, 3_ 4_ 5" ) # print( str( wrap_plus.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3 ) ) + " 1 2, 3 4_5 6, 7" ) - print( str( wrap_plus.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1 ) ) + " 1, 2_ 3_ 4_ 5" ) + # print( str( wrap_plus.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1 ) ) + " 1, 2_ 3_ 4_ 5" ) # print( str( wrap_plus.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3 ) ) + " 1 2, 3 4_5 6, 7" ) # print( str( "".join( wrap_plus.semantic_line_wrap( [ "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1" ], "% ", "% ", balance_characters_between_line_wraps=True ) ) ) ) - # print( "\n1 2 3 4.\n5 6 7, 1, 2, 3, 4, 5.\n6 7 8 9 1" ) + + wrap_plus.semantic_line_wrap( [ "% as boas práticas de programação (code clean, GOF, DEITEL (forminhas das boas práticas)). E deixa claro qual é o problema" ], "", "% ", balance_characters_between_line_wraps=True ) + # print( str( wrap_plus.is_comma_separated_list( "% as boas práticas de programação (code clean, GOF, DEITEL (forminhas das boas práticas)). E deixa claro qual é o problema", 45 ) ) + " % as boas práticas de programação (code clean, GOF, DEITEL (forminhas das boas práticas)). E deixa claro qual é o problema" ) # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "% ", "% ", balance_characters_between_line_wraps=True ) # wrap_plus.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "", "", balance_characters_between_line_wraps=True ) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index ce02356..474a657 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -209,48 +209,51 @@ def setUp(self): global maximum_words_in_comma_separated_list maximum_words_in_comma_separated_list = 4 + # is_comma_separated_list Unit Tests def test_is_command_separated_list_5_items(self): - self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, (True, 12) ) + self.is_comma_separated_list( "1, 2, 3, 4, 5", 1, (True, 12, 5) ) def test_is_command_separated_list_4_items(self): - self.is_comma_separated_list( "1, 2_ 3, 4, 5", 1, (True, 12) ) + self.is_comma_separated_list( "1, 2_ 3, 4, 5", 1, (True, 12, 4) ) def test_is_command_separated_list_3_items(self): - self.is_comma_separated_list( "1_ 2, 3, 4_ 5", 4, (True, 12) ) + self.is_comma_separated_list( "1_ 2, 3, 4_ 5", 4, (True, 12, 3) ) def test_is_command_separated_list_2_items(self): - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4, (True, 12) ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5", 4, (True, 12, 2) ) def test_is_command_separated_list_upperbound_with_1_by_5_trailing_items(self): - self.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1, (False, 0) ) + self.is_comma_separated_list( "1, 2_ 3_ 4_ 5", 1, (False, 0, 0) ) def test_is_command_separated_list_upperbound_with_4_middle_items(self): - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6, 7", 4, (False, 0) ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6, 7", 4, (False, 0, 0) ) def test_is_command_separated_list_upperbound_with_2_by_5_trailing_items(self): - self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6_ 7", 4, (False, 0) ) + self.is_comma_separated_list( "1_ 2, 3_ 4_ 5 6_ 7", 4, (False, 0, 0) ) def test_is_command_separated_list_upperbound_2_by_4_trailing_items(self): - self.is_comma_separated_list( "1_ 2, 3_ 4__5 6_ 7", 4, (False, 0) ) + self.is_comma_separated_list( "1_ 2, 3_ 4__5 6_ 7", 4, (False, 0, 0) ) def test_is_command_separated_list_lowerbound_with_3_items(self): - self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3, (True, 14) ) + self.is_comma_separated_list( "1 2, 3 4_5 6, 7", 3, (True, 14, 3) ) def test_is_command_separated_list_lowerbound_with_2_items(self): - self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 3, (True, 14) ) + self.is_comma_separated_list( "1 2, 3_4_5 6, 7", 3, (True, 14, 3) ) def test_is_command_separated_list_lowerbound_with_1_items(self): - self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 3, (True, 14) ) + self.is_comma_separated_list( "1 2, 3_4_5_6, 7", 3, (True, 14, 3) ) def test_is_command_separated_list_lowerbound_with_trailing_1_space(self): - self.is_comma_separated_list( "1 2, 3_ 4_5_6 7 ", 3, (True, 15) ) + self.is_comma_separated_list( "1 2, 3_ 4_5_6 7 ", 3, (True, 15, 2) ) def test_is_command_separated_list_lowerbound_with_trailing_2_space(self): - self.is_comma_separated_list( "1 2, 3_ 4_5_6 7 ", 3, (True, 16) ) + self.is_comma_separated_list( "1 2, 3_ 4_5_6 7 ", 3, (True, 16, 2) ) def is_comma_separated_list(self, text, index, goal): self.assertTrue( text[index] in wrap_plus_module.word_separator_characters ) self.assertEqual( goal, self.wrap_plus.is_comma_separated_list( text, index ) ) + + # semantic_line_wrap Unit Tests def test_semantic_line_wrap_simple_sentence(self): self.semantic_line_wrap( "1", "1" ) @@ -314,6 +317,13 @@ def test_semantic_line_wrap_with_initial_indentation(self): " tool,\n" " which will be certainly limited and still need to configure all over again." ) + def test_semantic_line_wrap_with_3_items_list(self): + self.semantic_line_wrap( [ "% as boas práticas de programação (code clean, GOF, DEITEL" + "(forminhas das boas práticas)). E deixa claro qual é o problema", "", "% " ], + "% as boas práticas de programação (code clean,\n" + "% GOF, DEITEL(forminhas das boas práticas)).\n" + "% E deixa claro qual é o problema" ) + def semantic_line_wrap(self, initial_text, goal): if isinstance( initial_text, list ): diff --git a/wrap_plus.py b/wrap_plus.py index 8f2abc1..5544e43 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -971,35 +971,34 @@ def force_flush_accumulated_line(): # the `comma_list_size` is lower than the `self._width`, otherwise the line will # be immediately flushed if comma_list_size > 0: - last_comma_list_size = comma_list_size comma_list_size -= 1 + last_comma_list_size = comma_list_size + 1 # print( "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, comma_list_end_point, character ) ) - if not is_flushing_accumalated_line: if not disable_line_wrapping_by_maximum_width \ and accumulated_line_length + next_word_length + indent_length > self._width: - # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) - is_flushing_accumalated_line = True - - # Current character is a whitespace, but it must the the next, so fix the index - index -= 1 + force_flush_accumulated_line() else: - accumulated_line += character - + accumulated_line += character is_flushing_comma_list = True continue else: - is_flushing_comma_list = False - is_comma_separated_list = False if last_comma_list_size == 1: last_comma_list_size = 0 - force_flush_accumulated_line() + + # It is not a comma separated list `if words_list_items_count < maximum_words_in_comma_separated_list` + # therefore we do not push a new line when flushing the processed contents by `is_comma_separated_list()` + if is_comma_separated_list: + force_flush_accumulated_line() + + is_flushing_comma_list = False + is_comma_separated_list = False # print( "semantic_line_wrap, index: %d, character: %s " % ( index, character ) ) if not disable_line_wrapping_by_maximum_width \ @@ -1022,9 +1021,12 @@ def force_flush_accumulated_line(): if character in word_separator_characters \ and not is_flushing_comma_list: - is_comma_separated_list, comma_list_end_point = self.is_comma_separated_list( text, index ) + is_comma_separated_list, comma_list_end_point, words_list_items_count = self.is_comma_separated_list( text, index ) comma_list_size = comma_list_end_point - ( index + 1 ) + if words_list_items_count < maximum_words_in_comma_separated_list: + is_comma_separated_list = False + # print( "semantic_line_wrap, index: %d, comma_list_size: %d" % ( index, comma_list_size ) ) if ( comma_list_size > 0 \ and not is_flushing_comma_list ) \ @@ -1085,6 +1087,9 @@ def is_comma_separated_list(self, text, index): # print( "is_comma_separated_list, index: %d" % ( index ) ) comma_list_end_point = -1 + # A word list has at least 2 items. For example: start 1, 2, 3 words + words_list_items_count = 2 + text_length = len( text ) - 1 words_counter = 0 @@ -1112,7 +1117,12 @@ def is_comma_separated_list(self, text, index): if is_word_separator_character and is_next_character_whitepace: if 0 < words_counter < maximum_words_in_comma_separated_list: - comma_list_end_point = index + comma_list_end_point = index + + # When the next character is '$', we cannot count it as a item as it is already + # set by the `words_list_items_count` default value `2` + if next_character != '$': + words_list_items_count += 1 else: break @@ -1120,11 +1130,11 @@ def is_comma_separated_list(self, text, index): words_counter = 0 if comma_list_end_point > -1: - # print( "is_comma_separated_list (True), comma_list_end_point: %d" % ( comma_list_end_point ) ) - return True, comma_list_end_point + # print( "is_comma_separated_list (True), comma_list_end_point: %d, words_list_items_count: %d" % ( comma_list_end_point, words_list_items_count ) ) + return True, comma_list_end_point, words_list_items_count - # print( "is_comma_separated_list (False), comma_list_end_point: %d" % ( 0 ) ) - return False, 0 + # print( "is_comma_separated_list (False), comma_list_end_point: %d, words_list_items_count: %d" % ( 0, 0 ) ) + return False, 0, 0 def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent_indent): orig_initial_indent = initial_indent @@ -1247,6 +1257,7 @@ def run_tests(): # "test_is_command_separated_list_lowerbound_with_2_items", # "test_is_command_separated_list_lowerbound_with_1_items", # "test_is_command_separated_list_lowerbound_with_trailing_1_space", + # "test_semantic_line_wrap_with_3_items_list", # "test_semantic_line_wrap_simple_sentence_with_dual_comma", # "test_semantic_line_wrap_with_initial_indentation", # "test_semantic_line_wrap_with_numeric_comma_list_on_the_end", From 91b0a5e0494c1d1ddc32c96ecaa7c9e443be01ad Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 25 Nov 2017 20:06:07 -0200 Subject: [PATCH 050/160] Created the setting semantic_maximum_items_in_comma_separated_list when wrapping lines, it will consider they to be a list of words if it contains less items then set on this setting, the comma separated list will not be considered a list of words. "WrapPlus.semantic_maximum_items_in_comma_separated_list": 3 --- Base File.sublime-settings | 14 ++++++++ tests/semantic_linefeed_unit_tests.py | 15 ++++++-- wrap_plus.py | 50 +++++++++++++++++---------- 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index b9caffc..84fad50 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -48,6 +48,20 @@ // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. "WrapPlus.semantic_maximum_words_in_comma_separated_list": 3, + // When wrapping lines, it will consider they to be a list of words if it contains + // less items then set on this setting, the comma separated list will not be + // considered a list of words. + // + // For example, the minimum comma separated list of words has 3 items: + // `it is about to begin a comma separated list of words with 1, 2, 3 items` + // + // If it has less than 3 items, it is not a list of words, it is just a single + // comma breaking two sentences: + // `this is just a single comma, breaking a sentence as in 1, 2 3 items sequence` + // + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + "WrapPlus.semantic_maximum_items_in_comma_separated_list": 3, + // The `semantic_line_wrap` detects the maximum line width and uses it to // limite/delimite the maximum line width. If you like your lines only to be // wrapped by delimiter characters, you can set this to true. diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 474a657..8c7c4e4 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -263,7 +263,7 @@ def test_semantic_line_wrap_simple_sentence_with_single_comma(self): def test_semantic_line_wrap_simple_sentence_with_dual_comma(self): self.semantic_line_wrap( "which will take, you, quite some time", - "which will take,\nyou, quite some time" ) + "which will take, you, quite some time" ) def test_semantic_line_wrap_long_word(self): self.semantic_line_wrap( "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime", @@ -317,11 +317,20 @@ def test_semantic_line_wrap_with_initial_indentation(self): " tool,\n" " which will be certainly limited and still need to configure all over again." ) + def test_semantic_line_wrap_with_0_items_list(self): + self.wrap_plus.maximum_items_in_comma_separated_list = 3 + self.semantic_line_wrap( [ "% as boas práticas de programação (code clean, GOF, DEITEL" + "(forminhas das boas práticas)). E deixa claro qual é o problema", "", "% " ], + "% as boas práticas de programação (code clean, GOF,\n" + "% DEITEL(forminhas das boas práticas)).\n" + "% E deixa claro qual é o problema" ) + def test_semantic_line_wrap_with_3_items_list(self): + self.wrap_plus.maximum_items_in_comma_separated_list = 4 self.semantic_line_wrap( [ "% as boas práticas de programação (code clean, GOF, DEITEL" "(forminhas das boas práticas)). E deixa claro qual é o problema", "", "% " ], - "% as boas práticas de programação (code clean,\n" - "% GOF, DEITEL(forminhas das boas práticas)).\n" + "% as boas práticas de programação (code clean, GOF,\n" + "% DEITEL(forminhas das boas práticas)).\n" "% E deixa claro qual é o problema" ) def semantic_line_wrap(self, initial_text, goal): diff --git a/wrap_plus.py b/wrap_plus.py index 5544e43..1718a4f 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -228,7 +228,6 @@ def CONCAT(*args): return '(?:' + ''.join(args) + ')' blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') -maximum_words_in_comma_separated_list = 4 next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) whitespace_character = (" ", "\t") @@ -265,6 +264,12 @@ def CONCAT(*args): class WrapLinesPlusCommand(sublime_plugin.TextCommand): + def __init__(self, view): + super( WrapLinesPlusCommand, self ).__init__( view ) + + self.maximum_words_in_comma_separated_list = 4 + self.maximum_items_in_comma_separated_list = 4 + def _my_full_line(self, region): # Special case scenario where you select an entire line. The normal # "full_line" function will extend it to contain the next line @@ -673,7 +678,6 @@ def run(self, edit, width=0): view_settings = self.view.settings() debug('paragraphs is %r', paragraphs) - global maximum_words_in_comma_separated_list break_long_words = view_settings.get('WrapPlus.break_long_words', True) break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) after_wrap = view_settings.get('WrapPlus.after_wrap', "cursor_below") @@ -681,7 +685,8 @@ def run(self, edit, width=0): minimum_line_size_percent = view_settings.get('WrapPlus.semantic_minimum_line_size_percent', 0.2) balance_characters_between_line_wraps = view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.semantic_disable_line_wrapping_by_maximum_width', False) - maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 + self.maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 + self.maximum_items_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_items_in_comma_separated_list', 3) + 1 wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) @@ -990,13 +995,14 @@ def force_flush_accumulated_line(): else: if last_comma_list_size == 1: - last_comma_list_size = 0 - # It is not a comma separated list `if words_list_items_count < maximum_words_in_comma_separated_list` + # It is not a comma separated list `if comma_separated_list_items_count < self.maximum_items_in_comma_separated_list` # therefore we do not push a new line when flushing the processed contents by `is_comma_separated_list()` if is_comma_separated_list: force_flush_accumulated_line() + last_comma_list_size = 0 + is_flushing_comma_list = False is_comma_separated_list = False @@ -1021,16 +1027,18 @@ def force_flush_accumulated_line(): if character in word_separator_characters \ and not is_flushing_comma_list: - is_comma_separated_list, comma_list_end_point, words_list_items_count = self.is_comma_separated_list( text, index ) + is_comma_separated_list, comma_list_end_point, comma_separated_list_items_count = self.is_comma_separated_list( text, index ) comma_list_size = comma_list_end_point - ( index + 1 ) - if words_list_items_count < maximum_words_in_comma_separated_list: + if comma_separated_list_items_count < maximum_words_in_comma_separated_list: is_comma_separated_list = False # print( "semantic_line_wrap, index: %d, comma_list_size: %d" % ( index, comma_list_size ) ) - if ( comma_list_size > 0 \ - and not is_flushing_comma_list ) \ - or not is_comma_separated_list \ + if ( is_comma_separated_list \ + and comma_list_size > -1 ) \ + and not is_flushing_comma_list \ + or ( not is_comma_separated_list and \ + comma_list_size < 0 ) \ or is_flushing_accumalated_line: # It is not the first line anymore, now we need to use the `subsequent_indent_length` @@ -1052,6 +1060,9 @@ def force_flush_accumulated_line(): is_allowed_to_wrap = False is_flushing_accumalated_line = False + else: + accumulated_line += character + else: accumulated_line += character @@ -1088,7 +1099,7 @@ def is_comma_separated_list(self, text, index): comma_list_end_point = -1 # A word list has at least 2 items. For example: start 1, 2, 3 words - words_list_items_count = 2 + comma_separated_list_items_count = 2 text_length = len( text ) - 1 words_counter = 0 @@ -1116,13 +1127,13 @@ def is_comma_separated_list(self, text, index): # print( "is_comma_separated_list, index: %d, words_counter: %d, character: %s, next_character: %s" % ( index, words_counter, character, next_character ) ) if is_word_separator_character and is_next_character_whitepace: - if 0 < words_counter < maximum_words_in_comma_separated_list: + if 0 < words_counter < self.maximum_words_in_comma_separated_list: comma_list_end_point = index # When the next character is '$', we cannot count it as a item as it is already - # set by the `words_list_items_count` default value `2` + # set by the `comma_separated_list_items_count` default value `2` if next_character != '$': - words_list_items_count += 1 + comma_separated_list_items_count += 1 else: break @@ -1130,10 +1141,10 @@ def is_comma_separated_list(self, text, index): words_counter = 0 if comma_list_end_point > -1: - # print( "is_comma_separated_list (True), comma_list_end_point: %d, words_list_items_count: %d" % ( comma_list_end_point, words_list_items_count ) ) - return True, comma_list_end_point, words_list_items_count + # print( "is_comma_separated_list (True), comma_list_end_point: %d, comma_separated_list_items_count: %d" % ( comma_list_end_point, comma_separated_list_items_count ) ) + return True, comma_list_end_point, comma_separated_list_items_count - # print( "is_comma_separated_list (False), comma_list_end_point: %d, words_list_items_count: %d" % ( 0, 0 ) ) + # print( "is_comma_separated_list (False), comma_list_end_point: %d, comma_separated_list_items_count: %d" % ( 0, 0 ) ) return False, 0, 0 def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent_indent): @@ -1257,10 +1268,11 @@ def run_tests(): # "test_is_command_separated_list_lowerbound_with_2_items", # "test_is_command_separated_list_lowerbound_with_1_items", # "test_is_command_separated_list_lowerbound_with_trailing_1_space", + # "test_semantic_line_wrap_with_0_items_list", + # "test_semantic_line_wrap_with_numeric_comma_list_on_the_end", # "test_semantic_line_wrap_with_3_items_list", # "test_semantic_line_wrap_simple_sentence_with_dual_comma", # "test_semantic_line_wrap_with_initial_indentation", - # "test_semantic_line_wrap_with_numeric_comma_list_on_the_end", # "test_balance_characters_between_line_wraps_commented_line", # "test_balance_characters_between_line_wraps_starting_with_comment", # "test_balance_characters_between_line_wraps_with_big_multi_line_balancing", @@ -1287,5 +1299,5 @@ def plugin_loaded(): https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line """ pass - run_tests() + # run_tests() From d54d434e763d19bf346213a38e251eb78ea33d55 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 26 Nov 2017 15:30:56 -0200 Subject: [PATCH 051/160] Fixed NameError: global name is not defined: 'maximum_words_in_comma_separated_list' --- wrap_plus.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 1718a4f..cf3de47 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -678,18 +678,18 @@ def run(self, edit, width=0): view_settings = self.view.settings() debug('paragraphs is %r', paragraphs) + after_wrap = view_settings.get('WrapPlus.after_wrap', "cursor_below") break_long_words = view_settings.get('WrapPlus.break_long_words', True) break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) - after_wrap = view_settings.get('WrapPlus.after_wrap', "cursor_below") minimum_line_size_percent = view_settings.get('WrapPlus.semantic_minimum_line_size_percent', 0.2) balance_characters_between_line_wraps = view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.semantic_disable_line_wrapping_by_maximum_width', False) - self.maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 - self.maximum_items_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_items_in_comma_separated_list', 3) + 1 - wrapper = textwrap.TextWrapper(break_long_words=break_long_words, - break_on_hyphens=break_on_hyphens) + self.maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 + self.maximum_items_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_items_in_comma_separated_list', 3) + 1 + + wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) wrapper.width = self._width wrapper.expand_tabs = False @@ -1030,7 +1030,7 @@ def force_flush_accumulated_line(): is_comma_separated_list, comma_list_end_point, comma_separated_list_items_count = self.is_comma_separated_list( text, index ) comma_list_size = comma_list_end_point - ( index + 1 ) - if comma_separated_list_items_count < maximum_words_in_comma_separated_list: + if comma_separated_list_items_count < self.maximum_words_in_comma_separated_list: is_comma_separated_list = False # print( "semantic_line_wrap, index: %d, comma_list_size: %d" % ( index, comma_list_size ) ) From 350369cfb95340034798da23498694c64b4ba18f Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 26 Nov 2017 15:53:43 -0200 Subject: [PATCH 052/160] Fixed wrong use of maximum_words_in_comma_separated_list instead of maximum_items_in_comma_separated_list and created Unit Tests for it. --- tests/semantic_linefeed_unit_tests.py | 9 ++++++++- wrap_plus.py | 5 +++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 8c7c4e4..0322a65 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -262,9 +262,15 @@ def test_semantic_line_wrap_simple_sentence_with_single_comma(self): "which will take,\nyou quite some time" ) def test_semantic_line_wrap_simple_sentence_with_dual_comma(self): + self.wrap_plus.maximum_items_in_comma_separated_list = 4 self.semantic_line_wrap( "which will take, you, quite some time", "which will take, you, quite some time" ) + def test_semantic_line_wrap_simple_sentence_with_dual_comma_with_3_items_minimum(self): + self.wrap_plus.maximum_items_in_comma_separated_list = 3 + self.semantic_line_wrap( "which will take, you, quite some time", + "which will take,\nyou, quite some time" ) + def test_semantic_line_wrap_long_word(self): self.semantic_line_wrap( "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime", "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ) @@ -321,7 +327,8 @@ def test_semantic_line_wrap_with_0_items_list(self): self.wrap_plus.maximum_items_in_comma_separated_list = 3 self.semantic_line_wrap( [ "% as boas práticas de programação (code clean, GOF, DEITEL" "(forminhas das boas práticas)). E deixa claro qual é o problema", "", "% " ], - "% as boas práticas de programação (code clean, GOF,\n" + "% as boas práticas de programação (code clean,\n" + "% GOF,\n" "% DEITEL(forminhas das boas práticas)).\n" "% E deixa claro qual é o problema" ) diff --git a/wrap_plus.py b/wrap_plus.py index cf3de47..03a0728 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1030,10 +1030,10 @@ def force_flush_accumulated_line(): is_comma_separated_list, comma_list_end_point, comma_separated_list_items_count = self.is_comma_separated_list( text, index ) comma_list_size = comma_list_end_point - ( index + 1 ) - if comma_separated_list_items_count < self.maximum_words_in_comma_separated_list: + if comma_separated_list_items_count < self.maximum_items_in_comma_separated_list: is_comma_separated_list = False - # print( "semantic_line_wrap, index: %d, comma_list_size: %d" % ( index, comma_list_size ) ) + # print( "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)" % ( index, comma_list_size, self.maximum_items_in_comma_separated_list ) ) if ( is_comma_separated_list \ and comma_list_size > -1 ) \ and not is_flushing_comma_list \ @@ -1268,6 +1268,7 @@ def run_tests(): # "test_is_command_separated_list_lowerbound_with_2_items", # "test_is_command_separated_list_lowerbound_with_1_items", # "test_is_command_separated_list_lowerbound_with_trailing_1_space", + # "test_semantic_line_wrap_simple_sentence_with_dual_comma_with_3_items_minimum", # "test_semantic_line_wrap_with_0_items_list", # "test_semantic_line_wrap_with_numeric_comma_list_on_the_end", # "test_semantic_line_wrap_with_3_items_list", From 29b7804b9d08a667f4e772631cb3918e8a7204c6 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 26 Nov 2017 16:14:36 -0200 Subject: [PATCH 053/160] Removed most tests form the test list on wrap_plus.py to clean up some space. --- wrap_plus.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 03a0728..417edd5 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1260,34 +1260,6 @@ def run_tests(): # "test_is_command_separated_list_4_items", # "test_is_command_separated_list_3_items", # "test_is_command_separated_list_2_items", - # "test_is_command_separated_list_upperbound_with_1_by_5_trailing_items", - # "test_is_command_separated_list_upperbound_with_4_middle_items", - # "test_is_command_separated_list_upperbound_with_2_by_5_trailing_items", - # "test_is_command_separated_list_upperbound_2_by_4_trailing_items", - # "test_is_command_separated_list_lowerbound_with_3_items", - # "test_is_command_separated_list_lowerbound_with_2_items", - # "test_is_command_separated_list_lowerbound_with_1_items", - # "test_is_command_separated_list_lowerbound_with_trailing_1_space", - # "test_semantic_line_wrap_simple_sentence_with_dual_comma_with_3_items_minimum", - # "test_semantic_line_wrap_with_0_items_list", - # "test_semantic_line_wrap_with_numeric_comma_list_on_the_end", - # "test_semantic_line_wrap_with_3_items_list", - # "test_semantic_line_wrap_simple_sentence_with_dual_comma", - # "test_semantic_line_wrap_with_initial_indentation", - # "test_balance_characters_between_line_wraps_commented_line", - # "test_balance_characters_between_line_wraps_starting_with_comment", - # "test_balance_characters_between_line_wraps_with_big_multi_line_balancing", - # "test_balance_characters_between_line_wraps_with_long_indentation_balance", - # "test_balance_characters_between_line_wraps_with_long_subsequent_indentation", - # "test_split_lines_with_long_subsequent_indentation", - # "test_calculate_lines_count_with_maximum_lines_indent", - # "test_calculate_lines_count_with_minimum_lines_indent", - # "test_semantic_line_wrap_line_starting_with_comment", - # "test_split_lines_with_trailing_new_line", - # "test_split_lines_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_with_trailing_new_line", - # "test_balance_characters_between_line_wraps_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_ending_with_long_word", ] semantic_linefeed_unit_tests.run_unit_tests( unit_tests_to_run ) From d6b8ed064c538690ba12c9c27aa036dbb9bd00d4 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 27 Nov 2017 20:41:40 -0200 Subject: [PATCH 054/160] Fixed UnboundLocalError: local variable 'disable_line_wrapping_by_maximum_width' referenced before assignment --- wrap_plus.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 417edd5..7a3bd4a 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -693,14 +693,14 @@ def run(self, edit, width=0): wrapper.width = self._width wrapper.expand_tabs = False + if balance_characters_between_line_wraps: + # minimum_line_size_percent = 0.0 + disable_line_wrapping_by_maximum_width = True + # print( "minimum_line_size_percent: " + str( minimum_line_size_percent ) ) if view_settings.get( 'WrapPlus.semantic_line_wrap', False ): def line_wrapper_type(): - if balance_characters_between_line_wraps: - # minimum_line_size_percent = 0.0 - disable_line_wrapping_by_maximum_width = True - text = self.semantic_line_wrap( paragraph_lines, initial_indent, subsequent_indent, minimum_line_size_percent, disable_line_wrapping_by_maximum_width, balance_characters_between_line_wraps ) From eb24f5338c6012a6451fd94cb01b0c87f6995594 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 27 Nov 2017 20:45:23 -0200 Subject: [PATCH 055/160] Partially implemented differentiation/distinction between commas and dots while computing comma separated list. There is still to analyze and fix the wrap_plus.py Unit Tests accordingly to this new feature. Currently there are: Ran 45 tests in 0.203s FAILED (failures=7) --- wrap_plus.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 7a3bd4a..e75c45d 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -231,7 +231,8 @@ def CONCAT(*args): next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) whitespace_character = (" ", "\t") -word_separator_characters = ( ",", ".", "?", "!", ":", ";" ) +list_separator_characters = ( ",", ";" ) +word_separator_characters = ( ".", "?", "!", ":" ) + list_separator_characters # This doesn't always work, but seems decent. numbered_list = r'(?:(?:[0-9#]+[.)])+[\t ])' @@ -1024,13 +1025,19 @@ def force_flush_accumulated_line(): if is_followed_by_space: - if character in word_separator_characters \ - and not is_flushing_comma_list: + if not is_flushing_comma_list: - is_comma_separated_list, comma_list_end_point, comma_separated_list_items_count = self.is_comma_separated_list( text, index ) - comma_list_size = comma_list_end_point - ( index + 1 ) + if character in list_separator_characters: + is_comma_separated_list, comma_list_end_point, comma_separated_list_items_count = \ + self.is_comma_separated_list( text, index ) - if comma_separated_list_items_count < self.maximum_items_in_comma_separated_list: + comma_list_size = comma_list_end_point - ( index + 1 ) + + if comma_separated_list_items_count < self.maximum_items_in_comma_separated_list: + is_comma_separated_list = False + + elif character in word_separator_characters: + comma_list_size = -1 is_comma_separated_list = False # print( "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)" % ( index, comma_list_size, self.maximum_items_in_comma_separated_list ) ) @@ -1112,7 +1119,7 @@ def is_comma_separated_list(self, text, index): if index < text_length: next_character = text[index+1] - is_word_separator_character = character in word_separator_characters + is_word_separator_character = character in list_separator_characters is_next_character_whitepace = next_character in whitespace_character else: @@ -1128,7 +1135,7 @@ def is_comma_separated_list(self, text, index): if is_word_separator_character and is_next_character_whitepace: if 0 < words_counter < self.maximum_words_in_comma_separated_list: - comma_list_end_point = index + comma_list_end_point = index # When the next character is '$', we cannot count it as a item as it is already # set by the `comma_separated_list_items_count` default value `2` From 9a6b5ee6f1247ef5b0823d76f7f09b7b0339a8cb Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 3 Dec 2017 21:37:27 -0200 Subject: [PATCH 056/160] Fixed the Unit Tests for the last implemented feature, issue: [Wrap Plus] Create Unit Tests and fix the C++/Rust documentation styles https://github.com/evandrocoan/SublimeStudio/issues/75 --- tests/semantic_linefeed_unit_tests.py | 18 +++++++++++------- wrap_plus.py | 6 ++++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 0322a65..f9df36f 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -277,7 +277,11 @@ def test_semantic_line_wrap_long_word(self): def test_semantic_line_wrap_ending_with_comma_list(self): self.semantic_line_wrap( "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc.", - "you still only configuring a few languages closely related.\nOn this case, C, C++, Java, Pawn, etc." ) + "you still only configuring a few languages closely related.\nOn this case,\nC, C++, Java, Pawn,\netc." ) + + def test_semantic_line_wrap_ending_with_trailling_comma_on_list(self): + self.semantic_line_wrap( "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc,", + "you still only configuring a few languages closely related.\nOn this case,\nC, C++, Java, Pawn, etc," ) def test_semantic_line_wrap_with_comma_list_on_the_middle(self): self.semantic_line_wrap( "which will not more take, you quite oh the time, some time, more time, the time, per time", @@ -285,11 +289,11 @@ def test_semantic_line_wrap_with_comma_list_on_the_middle(self): def test_semantic_line_wrap_with_comma_list_on_the_end(self): self.semantic_line_wrap( "few languages close related. On this case, C, C++, Java, Pawn, etc. more over break this line", - "few languages close related.\nOn this case, C, C++, Java, Pawn, etc.\nmore over break this line" ) + "few languages close related.\nOn this case,\nC, C++, Java, Pawn,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_numeric_comma_list_on_the_end(self): self.semantic_line_wrap( "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1", - "1 2 3 4.\n5 6 7, 1, 2, 3, 4, 5.\n6 7 8 9 1" ) + "1 2 3 4.\n5 6 7,\n1, 2, 3, 4,\n5.\n6 7 8 9 1" ) def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): self.semantic_line_wrap( "For all other languages you still need to find out another source code " @@ -302,19 +306,19 @@ def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): def test_semantic_line_wrap_with_80_characters(self): self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], - "few languages close related.\nOn this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program,\nassure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) + "few languages close related.\nOn this case,\nC, C++, Javas, Pawn, if, you, already, had, written, the, program, assure,\neverything, is, under, versioning, control, system, and, broke, everything,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_79_characters(self): self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], - "few languages close related.\nOn this case, C, C++, Java, Pawn, if, you, already, had, written, the, program,\nassure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) + "few languages close related.\nOn this case,\nC, C++, Java, Pawn, if, you, already, had, written, the, program, assure,\neverything, is, under, versioning, control, system, and, broke, everything,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_81_characters(self): self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], - "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprogram, assure, everything, is, under, versioning, control, system, and, broke,\neverything, etc.\nmore over break this line" ) + "few languages close related.\nOn this case,\nC, C++, Javas, Pawns, if, you, already, had, written, the, program, assure,\neverything, is, under, versioning, control, system, and, broke, everything,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_81_characters_on_list_flushing(self): self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], - "few languages close related.\nOn this case, C, C++, Javas, Pawns, if, you, already, had, written, the,\nprograms, assure, everything, is, under, versioning, control, system, and,\nbroke, everything, etc.\nmore over break this line" ) + "few languages close related.\nOn this case,\nC, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure,\neverything, is, under, versioning, control, system, and, broke, everything,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_initial_indentation(self): self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " diff --git a/wrap_plus.py b/wrap_plus.py index e75c45d..af93c46 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -233,6 +233,7 @@ def CONCAT(*args): whitespace_character = (" ", "\t") list_separator_characters = ( ",", ";" ) word_separator_characters = ( ".", "?", "!", ":" ) + list_separator_characters +phrase_separator_characters = set( word_separator_characters ) - set( list_separator_characters ) # This doesn't always work, but seems decent. numbered_list = r'(?:(?:[0-9#]+[.)])+[\t ])' @@ -1124,7 +1125,7 @@ def is_comma_separated_list(self, text, index): else: next_character = '$' - is_word_separator_character = True + is_word_separator_character = character not in phrase_separator_characters is_next_character_whitepace = True # We count a word before it begins and set `comma_list_end_point` when we find a space after a comma @@ -1263,6 +1264,7 @@ def run_tests(): # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ + # "test_semantic_line_wrap_ending_with_comma_list", # "test_is_command_separated_list_5_items", # "test_is_command_separated_list_4_items", # "test_is_command_separated_list_3_items", @@ -1279,5 +1281,5 @@ def plugin_loaded(): https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line """ pass - # run_tests() + run_tests() From e3cc63c88a486320892edae811da59547ccc4da1 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 3 Dec 2017 22:30:47 -0200 Subject: [PATCH 057/160] Replaced reload_package by sublime_plugin.reload_plugin on wrap_plus.py --- wrap_plus.py | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index af93c46..703a4e6 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1236,27 +1236,14 @@ def input_package(self, width): self.view.run_command( 'wrap_lines_plus', { 'width': int( width ) } ) -def reload_package(full_module_name): - import imp - import sys - import importlib - - if full_module_name in sys.modules: - module_object = sys.modules[full_module_name] - module_object = imp.reload( module_object ) - - else: - importlib.import_module( full_module_name ) - - def run_tests(): """ How do I unload (reload) a Python module? https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module """ print( "\n\n" ) - reload_package( "Wrap Plus.tests.semantic_linefeed_unit_tests" ) - reload_package( "Wrap Plus.tests.semantic_linefeed_manual_tests" ) + sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_unit_tests" ) + sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_manual_tests" ) from .tests import semantic_linefeed_unit_tests from .tests import semantic_linefeed_manual_tests @@ -1281,5 +1268,5 @@ def plugin_loaded(): https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line """ pass - run_tests() + # run_tests() From 6b9fa72297838c739ffc61479aad4cba5f212816 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 4 Dec 2017 00:48:48 -0200 Subject: [PATCH 058/160] Created the tests/text_extraction_unit_tests.py initial structure for the wrap_plus.py text extraction features. --- tests/semantic_linefeed_unit_tests.py | 12 ++--- tests/text_extraction_unit_tests.py | 65 +++++++++++++++++++++++++++ wrap_plus.py | 23 ++++++---- 3 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 tests/text_extraction_unit_tests.py diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index f9df36f..8e50cba 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -2,10 +2,13 @@ import sys +import sublime +import sublime_plugin + import textwrap import unittest - +from .text_extraction_unit_tests import PrefixStrippingViewUnitTests wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] @@ -14,12 +17,12 @@ def run_unit_tests(unit_tests_to_run=[]): classes = \ [ - SemanticLineWrapUnitTests, - LineBalancingUnitTests, + PrefixStrippingViewUnitTests, + # SemanticLineWrapUnitTests, + # LineBalancingUnitTests, ] if len( unit_tests_to_run ) < 1: - # Comment all the tests names on this list, to run all Unit Tests unit_tests_to_run = \ [ @@ -34,7 +37,6 @@ def run_unit_tests(unit_tests_to_run=[]): runner.run( suite( classes, unit_tests_to_run ) ) - class LineBalancingUnitTests(unittest.TestCase): @classmethod diff --git a/tests/text_extraction_unit_tests.py b/tests/text_extraction_unit_tests.py new file mode 100644 index 0000000..6bcbb03 --- /dev/null +++ b/tests/text_extraction_unit_tests.py @@ -0,0 +1,65 @@ + + +import sys + +import sublime +import sublime_plugin + +import textwrap +import unittest + + +wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] + + +def wrap_text(text): + return textwrap.dedent( text ).strip( " " ).strip( "\n" ) + + +class PrefixStrippingViewUnitTests(unittest.TestCase): + + @classmethod + def setUp(self): + self.maxDiff = None + + # Create a new Sublime Text view to perform the Unit Tests + self.view = sublime.active_window().new_file() + self.view.set_syntax_file( "Packages/C++/C++.sublime-syntax" ) + + # make sure we have a window to work with + settings = sublime.load_settings("Preferences.sublime-settings") + settings.set("close_windows_when_empty", False) + + def tearDown(self): + if self.view: + self.view.set_scratch(True) + self.view.window().focus_view(self.view) + self.view.window().run_command("close_file") + + def setText(self, string): + self.view.run_command("append", {"characters": wrap_text( string ) }) + + def test_triple_doxygen_quotes_comment(self): + view_min = 0 + view_max = 57 + + self.setText( """\ + /// This is a doxygen + /// style multiline + /// C++ comment. + """ ) + + self.wrap_plus = wrap_plus_module.WrapLinesPlusCommand( None ) + self.wrap_plus.view = self.view + self.wrap_plus._width = 50 + + self.wrap_plus._determine_tab_size() + self.wrap_plus._determine_comment_style() + + paragraph_results = self.wrap_plus._find_paragraphs( sublime.Region(view_min, view_max) ) + region, paragraphs, comment_prefix = paragraph_results[0] + + print( "self.wrap_plus._find_paragraphs: " + str( paragraph_results ) ) + # self.assertEqual( '///', comment_prefix ) + + diff --git a/wrap_plus.py b/wrap_plus.py index 703a4e6..281a7b2 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -61,6 +61,11 @@ class PrefixStrippingView(object): required_comment_pattern = None def __init__(self, view, min, max): + """ + @param view the Sublime Text view from where to get the text from + @min the view start point to extract the text from + @max the view end point to extract the text from + """ self.view = view self.min = min self.max = max @@ -353,10 +358,10 @@ def _find_paragraph_start(self, point): current_line = prev_line return current_line_region, current_line - def _find_paragraphs(self, sr): + def _find_paragraphs(self, sublime_text_region): """Find and return a list of paragraphs as regions. - :param Region sr: The region where to look for paragraphs. If it is + :param Region sublime_text_region: The region where to look for paragraphs. If it is an empty region, "discover" where the paragraph starts and ends. Otherwise, the region defines the max and min (with potentially several paragraphs contained within). @@ -364,21 +369,21 @@ def _find_paragraphs(self, sr): :returns: A list of (region, lines, comment_prefix) of each paragraph. """ result = [] - debug('find paragraphs sr=%r', sr,) - if sr.empty(): + debug('find paragraphs sublime_text_region=%r', sublime_text_region,) + if sublime_text_region.empty(): is_empty = True view_min = 0 view_max = self.view.size() else: is_empty = False - full_sr = self._my_full_line(sr) + full_sr = self._my_full_line(sublime_text_region) view_min = full_sr.begin() view_max = full_sr.end() - started_in_comment = self._started_in_comment(sr.begin()) + started_in_comment = self._started_in_comment(sublime_text_region.begin()) self._strip_view = PrefixStrippingView(self.view, view_min, view_max) view = self._strip_view - # Loop for each paragraph (only loops once if sr is empty). - paragraph_start_pt = sr.begin() + # Loop for each paragraph (only loops once if sublime_text_region is empty). + paragraph_start_pt = sublime_text_region.begin() while 1: debug('paragraph scanning start %r.', paragraph_start_pt,) view.set_comments(self._line_comment, self._is_block_comment, paragraph_start_pt) @@ -1268,5 +1273,5 @@ def plugin_loaded(): https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line """ pass - # run_tests() + run_tests() From c36c17bc547ff4f20e4bb1f705ed6c446b65359b Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 4 Dec 2017 16:14:52 -0200 Subject: [PATCH 059/160] Fixed C++/Rust documentation prefix styles and created Unit Tests on text_extraction_unit_tests.py, issue: https://github.com/evandrocoan/SublimeStudio/issues/75 --- tests/semantic_linefeed_unit_tests.py | 4 +- tests/text_extraction_unit_tests.py | 79 ++++++++++++++++++++++----- wrap_plus.py | 22 +++++--- 3 files changed, 80 insertions(+), 25 deletions(-) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 8e50cba..fab4250 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -18,8 +18,8 @@ def run_unit_tests(unit_tests_to_run=[]): classes = \ [ PrefixStrippingViewUnitTests, - # SemanticLineWrapUnitTests, - # LineBalancingUnitTests, + SemanticLineWrapUnitTests, + LineBalancingUnitTests, ] if len( unit_tests_to_run ) < 1: diff --git a/tests/text_extraction_unit_tests.py b/tests/text_extraction_unit_tests.py index 6bcbb03..a0465c2 100644 --- a/tests/text_extraction_unit_tests.py +++ b/tests/text_extraction_unit_tests.py @@ -36,19 +36,9 @@ def tearDown(self): self.view.window().focus_view(self.view) self.view.window().run_command("close_file") - def setText(self, string): + def setText(self, string, start_point=0): self.view.run_command("append", {"characters": wrap_text( string ) }) - def test_triple_doxygen_quotes_comment(self): - view_min = 0 - view_max = 57 - - self.setText( """\ - /// This is a doxygen - /// style multiline - /// C++ comment. - """ ) - self.wrap_plus = wrap_plus_module.WrapLinesPlusCommand( None ) self.wrap_plus.view = self.view self.wrap_plus._width = 50 @@ -56,10 +46,71 @@ def test_triple_doxygen_quotes_comment(self): self.wrap_plus._determine_tab_size() self.wrap_plus._determine_comment_style() - paragraph_results = self.wrap_plus._find_paragraphs( sublime.Region(view_min, view_max) ) + selections = self.view.sel() + selections.clear() + selections.add( sublime.Region( start_point, start_point ) ) + + def get_view_contents(self): + return self.view.substr( sublime.Region( 0, self.view.size() - 1 ) ) + + def test_triple_quotes_comment(self): + self.setText( """\ + /// This is a doxygen + /// style multiline + /// C++ comment.""" ) + + paragraph_results = self.wrap_plus._find_paragraphs( sublime.Region(0, 0) ) region, paragraphs, comment_prefix = paragraph_results[0] - print( "self.wrap_plus._find_paragraphs: " + str( paragraph_results ) ) - # self.assertEqual( '///', comment_prefix ) + # print( "self.wrap_plus._find_paragraphs: " + str( paragraph_results ) ) + self.assertEqual( '///', comment_prefix ) + self.assertEqual( sublime.Region(0, 58), region ) + def test_triple_quotes_wrappting(self): + self.setText( """\ + /// This is a doxygen is a doxygen is a doxygen is a doxygen + /// style multiline + /// C++ comment.""" ) + + self.view.run_command( "wrap_lines_plus", {"width": 50} ) + self.assertEqual( wrap_text( """\ + /// This is a doxygen is a doxygen is a doxygen is + /// a doxygen style multiline C++ comment""" ), + self.get_view_contents() ) + + def test_double_quotes_wrappting(self): + self.setText( """\ + // This is a doxygen is a doxygen is a doxygen is a doxygen + // style multiline + // C++ comment.""" ) + + self.view.run_command( "wrap_lines_plus", {"width": 50} ) + self.assertEqual( wrap_text( """\ + // This is a doxygen is a doxygen is a doxygen is + // a doxygen style multiline C++ comment""" ), + self.get_view_contents() ) + + def test_double_quotes_wrappting_without_leading_whitespace(self): + self.setText( """\ + //This is a doxygen is a doxygen is a doxygen is a doxygen + //style multiline + //C++ comment.""" ) + + self.view.run_command( "wrap_lines_plus", {"width": 50} ) + self.assertEqual( wrap_text( """\ + //This is a doxygen is a doxygen is a doxygen is a + //doxygen style multiline C++ comment""" ), + self.get_view_contents() ) + + def test_triple_quotes_wrappting_without_leading_whitespace(self): + self.setText( """\ + ///This is a doxygen is a doxygen is a doxygen is a doxygen + ///style multiline + ///C++ comment.""" ) + + self.view.run_command( "wrap_lines_plus", {"width": 50} ) + self.assertEqual( wrap_text( """\ + ///This is a doxygen is a doxygen is a doxygen is + ///a doxygen style multiline C++ comment""" ), + self.get_view_contents() ) diff --git a/wrap_plus.py b/wrap_plus.py index 281a7b2..fe61022 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -111,7 +111,11 @@ def set_comments(self, line_comments, block_comment, point): if is_generic_config: line_comments.extend([("//", False), ("#", False), ("%", False)]) - for line_comment, is_block_comment in line_comments: + extended_prefixes = [] + for prefix, is_block_comment in line_comments: + extended_prefixes.append( (prefix + prefix[-1], is_block_comment) ) + + for line_comment, is_block_comment in extended_prefixes: line_comment = line_comment.rstrip() debug( ( "line_comment: %s, line_stripped: %s" % ( line_comment, line_stripped ) ).replace("%", "%%") ) @@ -120,8 +124,7 @@ def set_comments(self, line_comments, block_comment, point): line_difference = len(line) - len(line.lstrip()) prefix = line[:line_difference+len(line_comment)] - if self.required_comment_prefix is None or \ - len(self.required_comment_prefix) < len(prefix): + if len(self.required_comment_prefix) < len(prefix): self.required_comment_prefix = prefix # TODO: re.escape required_comment_prefix. @@ -429,15 +432,15 @@ def _find_paragraphs(self, sublime_text_region): # Just in case something is wonky with the scope. end_pt = max(comment_r.begin(), current_line_region.begin()) # A substring of current_line. - subline_r = sublime.Region(current_line_region.begin(), end_pt) - subline = self.view.substr(subline_r) + sublime_region = sublime.Region(current_line_region.begin(), end_pt) + region_substring = self.view.substr(sublime_region) # Do not include whitespace preceding the comment. - regex_match = re.search('([ \t]+$)', subline) + regex_match = re.search('([ \t]+$)', region_substring) if regex_match: end_pt -= len(regex_match.group(1)) - debug('non-comment contents are: %r', subline) + debug('non-comment contents are: %r', region_substring) paragraph_end_pt = end_pt - lines.append(subline) + lines.append(region_substring) # Skip over the comment. current_line_region, current_line = view.next_line(current_line_region) break @@ -1247,6 +1250,7 @@ def run_tests(): https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module """ print( "\n\n" ) + sublime_plugin.reload_plugin( "Wrap Plus.tests.text_extraction_unit_tests" ) sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_unit_tests" ) sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_manual_tests" ) @@ -1273,5 +1277,5 @@ def plugin_loaded(): https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line """ pass - run_tests() + # run_tests() From 4c89728047935482dd10cad7a94f90a19e765eee Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 4 Dec 2017 16:44:23 -0200 Subject: [PATCH 060/160] Fixed the UnitTesting package not running the Unit Tests, issue: SystemError: Parent module '' not loaded, cannot perform relative import https://github.com/randy3k/UnitTesting/issues/67 --- tests/semantic_linefeed_unit_tests.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index fab4250..76ec336 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -8,7 +8,6 @@ import textwrap import unittest -from .text_extraction_unit_tests import PrefixStrippingViewUnitTests wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] @@ -17,7 +16,7 @@ def run_unit_tests(unit_tests_to_run=[]): classes = \ [ - PrefixStrippingViewUnitTests, + sys.modules["Wrap Plus.tests.text_extraction_unit_tests"].PrefixStrippingViewUnitTests, SemanticLineWrapUnitTests, LineBalancingUnitTests, ] From e9bb88460686b64c35f706a0b7c7b4157d9992cb Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 4 Dec 2017 16:54:48 -0200 Subject: [PATCH 061/160] Split/created the tests/unit_tests_runner.py from inside the tests/semantic_linefeed_unit_tests.py testing file. --- tests/semantic_linefeed_unit_tests.py | 59 ------------------------- tests/unit_tests_runner.py | 62 +++++++++++++++++++++++++++ wrap_plus.py | 5 ++- 3 files changed, 65 insertions(+), 61 deletions(-) create mode 100644 tests/unit_tests_runner.py diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 76ec336..1fa6f0b 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -2,40 +2,12 @@ import sys -import sublime -import sublime_plugin - import textwrap import unittest wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] -def run_unit_tests(unit_tests_to_run=[]): - runner = unittest.TextTestRunner() - - classes = \ - [ - sys.modules["Wrap Plus.tests.text_extraction_unit_tests"].PrefixStrippingViewUnitTests, - SemanticLineWrapUnitTests, - LineBalancingUnitTests, - ] - - if len( unit_tests_to_run ) < 1: - # Comment all the tests names on this list, to run all Unit Tests - unit_tests_to_run = \ - [ - # "test_semantic_line_wrap_line_starting_with_comment", - # "test_split_lines_with_trailing_new_line", - # "test_split_lines_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_with_trailing_new_line", - # "test_balance_characters_between_line_wraps_without_trailing_new_line", - # "test_balance_characters_between_line_wraps_ending_with_long_word", - ] - - runner.run( suite( classes, unit_tests_to_run ) ) - - class LineBalancingUnitTests(unittest.TestCase): @classmethod @@ -354,34 +326,3 @@ def semantic_line_wrap(self, initial_text, goal): self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) ) -def suite(classes, unit_tests_to_run): - """ - Problem with sys.argv[1] when unittest module is in a script - https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script - - Is there a way to loop through and execute all of the functions in a Python class? - https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute-all-of-the-functions - - looping over all member variables of a class in python - https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python - """ - suite = unittest.TestSuite() - unit_tests_to_run_count = len( unit_tests_to_run ) - - for _class in classes: - _object = _class() - - for function_name in dir( _object ): - - if function_name.lower().startswith( "test" ): - - if unit_tests_to_run_count > 0 \ - and function_name not in unit_tests_to_run: - - continue - - suite.addTest( _class( function_name ) ) - - return suite - - diff --git a/tests/unit_tests_runner.py b/tests/unit_tests_runner.py new file mode 100644 index 0000000..6bd9544 --- /dev/null +++ b/tests/unit_tests_runner.py @@ -0,0 +1,62 @@ + + +import sys +import unittest + +def run_unit_tests(unit_tests_to_run=[]): + runner = unittest.TextTestRunner() + + classes = \ + [ + sys.modules["Wrap Plus.tests.text_extraction_unit_tests"].PrefixStrippingViewUnitTests, + sys.modules["Wrap Plus.tests.semantic_linefeed_unit_tests"].LineBalancingUnitTests, + sys.modules["Wrap Plus.tests.semantic_linefeed_unit_tests"].SemanticLineWrapUnitTests, + ] + + if len( unit_tests_to_run ) < 1: + + # Comment all the tests names on this list, to run all Unit Tests + unit_tests_to_run = \ + [ + # "test_semantic_line_wrap_line_starting_with_comment", + # "test_split_lines_with_trailing_new_line", + # "test_split_lines_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_with_trailing_new_line", + # "test_balance_characters_between_line_wraps_without_trailing_new_line", + # "test_balance_characters_between_line_wraps_ending_with_long_word", + ] + + runner.run( suite( classes, unit_tests_to_run ) ) + + +def suite(classes, unit_tests_to_run): + """ + Problem with sys.argv[1] when unittest module is in a script + https://stackoverflow.com/questions/2812218/problem-with-sys-argv1-when-unittest-module-is-in-a-script + + Is there a way to loop through and execute all of the functions in a Python class? + https://stackoverflow.com/questions/2597827/is-there-a-way-to-loop-through-and-execute-all-of-the-functions + + looping over all member variables of a class in python + https://stackoverflow.com/questions/1398022/looping-over-all-member-variables-of-a-class-in-python + """ + suite = unittest.TestSuite() + unit_tests_to_run_count = len( unit_tests_to_run ) + + for _class in classes: + _object = _class() + + for function_name in dir( _object ): + + if function_name.lower().startswith( "test" ): + + if unit_tests_to_run_count > 0 \ + and function_name not in unit_tests_to_run: + + continue + + suite.addTest( _class( function_name ) ) + + return suite + + diff --git a/wrap_plus.py b/wrap_plus.py index fe61022..562321c 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1250,11 +1250,12 @@ def run_tests(): https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module """ print( "\n\n" ) + sublime_plugin.reload_plugin( "Wrap Plus.tests.unit_tests_runner" ) sublime_plugin.reload_plugin( "Wrap Plus.tests.text_extraction_unit_tests" ) sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_unit_tests" ) sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_manual_tests" ) - from .tests import semantic_linefeed_unit_tests + from .tests import unit_tests_runner from .tests import semantic_linefeed_manual_tests # Comment all the tests names on this list, to run all Unit Tests @@ -1267,7 +1268,7 @@ def run_tests(): # "test_is_command_separated_list_2_items", ] - semantic_linefeed_unit_tests.run_unit_tests( unit_tests_to_run ) + unit_tests_runner.run_unit_tests( unit_tests_to_run ) # semantic_linefeed_manual_tests.run_manual_tests() From 0be625ec68923620f96a54ce3e46f79d207f80cd Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 5 Dec 2017 14:48:10 -0200 Subject: [PATCH 062/160] Fixed prefixes being cut after extension --- unittesting.json | 2 +- wrap_plus.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/unittesting.json b/unittesting.json index af1e7b3..e5633c6 100644 --- a/unittesting.json +++ b/unittesting.json @@ -4,6 +4,6 @@ "async": false, "deferred": false, "verbosity": 2, - "capture_console": false, + "capture_console": true, "output": null } diff --git a/wrap_plus.py b/wrap_plus.py index 562321c..b8a9c56 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -112,7 +112,11 @@ def set_comments(self, line_comments, block_comment, point): line_comments.extend([("//", False), ("#", False), ("%", False)]) extended_prefixes = [] + + # Fix the C++/Rust extended prefix documentation styles + # https://github.com/evandrocoan/SublimeStudio/issues/75 for prefix, is_block_comment in line_comments: + extended_prefixes.append( (prefix, is_block_comment) ) extended_prefixes.append( (prefix + prefix[-1], is_block_comment) ) for line_comment, is_block_comment in extended_prefixes: From a31569c807dd95bd5785abc7744b6bfef800670a Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 5 Dec 2017 22:59:28 -0200 Subject: [PATCH 063/160] Setting verbosity unittesting.json's setting to 1 to reduce the produced output and help increase the run time. --- unittesting.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittesting.json b/unittesting.json index e5633c6..e59fac8 100644 --- a/unittesting.json +++ b/unittesting.json @@ -3,7 +3,7 @@ "pattern" : "*unit_tests.py", "async": false, "deferred": false, - "verbosity": 2, + "verbosity": 1, "capture_console": true, "output": null } From 1288716c4af1c6cfbdca747bf4b36f4faa1c1845 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 7 Dec 2017 22:54:19 -0200 Subject: [PATCH 064/160] Disabled .semantic_balance_characters_between_line_wraps by default on Base File.sublime-settings, due not being much useful. --- Base File.sublime-settings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 84fad50..983cd50 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -29,7 +29,7 @@ // will wrap near its end, // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. - "WrapPlus.semantic_balance_characters_between_line_wraps": true, + "WrapPlus.semantic_balance_characters_between_line_wraps": false, // The minimum of the percentage of the current maximum line width a line can // have. For example, if you `wrap_width` is set to 100, and you set this to `0.2`, From 2ad5cc95ac79536a31645b9243174b36f02c448d Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 8 Dec 2017 00:03:20 -0200 Subject: [PATCH 065/160] Fixed the hard coded class name usage. --- tests/unit_tests_runner.py | 10 +++++++--- wrap_plus.py | 11 +++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/unit_tests_runner.py b/tests/unit_tests_runner.py index 6bd9544..0528032 100644 --- a/tests/unit_tests_runner.py +++ b/tests/unit_tests_runner.py @@ -3,14 +3,18 @@ import sys import unittest +CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) +CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] + + def run_unit_tests(unit_tests_to_run=[]): runner = unittest.TextTestRunner() classes = \ [ - sys.modules["Wrap Plus.tests.text_extraction_unit_tests"].PrefixStrippingViewUnitTests, - sys.modules["Wrap Plus.tests.semantic_linefeed_unit_tests"].LineBalancingUnitTests, - sys.modules["Wrap Plus.tests.semantic_linefeed_unit_tests"].SemanticLineWrapUnitTests, + sys.modules[CURRENT_PACKAGE_NAME + ".tests.text_extraction_unit_tests"].PrefixStrippingViewUnitTests, + sys.modules[CURRENT_PACKAGE_NAME + ".tests.semantic_linefeed_unit_tests"].LineBalancingUnitTests, + sys.modules[CURRENT_PACKAGE_NAME + ".tests.semantic_linefeed_unit_tests"].SemanticLineWrapUnitTests, ] if len( unit_tests_to_run ) < 1: diff --git a/wrap_plus.py b/wrap_plus.py index b8a9c56..4e9a22a 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1253,11 +1253,14 @@ def run_tests(): How do I unload (reload) a Python module? https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module """ + CURRENT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) ) + CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] + print( "\n\n" ) - sublime_plugin.reload_plugin( "Wrap Plus.tests.unit_tests_runner" ) - sublime_plugin.reload_plugin( "Wrap Plus.tests.text_extraction_unit_tests" ) - sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_unit_tests" ) - sublime_plugin.reload_plugin( "Wrap Plus.tests.semantic_linefeed_manual_tests" ) + sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.unit_tests_runner" ) + sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.text_extraction_unit_tests" ) + sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.semantic_linefeed_unit_tests" ) + sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.semantic_linefeed_manual_tests" ) from .tests import unit_tests_runner from .tests import semantic_linefeed_manual_tests From 6f4f35ef253befd56d052ec546b871cbaa2c306b Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 8 Dec 2017 01:48:34 -0200 Subject: [PATCH 066/160] Fixed missing os import error --- tests/unit_tests_runner.py | 1 + wrap_plus.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/unit_tests_runner.py b/tests/unit_tests_runner.py index 0528032..f3eee72 100644 --- a/tests/unit_tests_runner.py +++ b/tests/unit_tests_runner.py @@ -1,5 +1,6 @@ +import os import sys import unittest diff --git a/wrap_plus.py b/wrap_plus.py index 4e9a22a..05f592f 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -2,6 +2,8 @@ import sublime, sublime_plugin import textwrap import re + +import os import math import time import unittest From 60704cfe78ddebeb6c5e10cb549e860977583ba0 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 8 Dec 2017 01:50:12 -0200 Subject: [PATCH 067/160] Created a unit test for badly wraps ``` inside list, issue: [Wrap Plus] Calling `Alt+Q` badly wraps ``` inside list https://github.com/evandrocoan/ITE/issues/61 --- tests/text_extraction_unit_tests.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/tests/text_extraction_unit_tests.py b/tests/text_extraction_unit_tests.py index a0465c2..aab3674 100644 --- a/tests/text_extraction_unit_tests.py +++ b/tests/text_extraction_unit_tests.py @@ -51,7 +51,7 @@ def setText(self, string, start_point=0): selections.add( sublime.Region( start_point, start_point ) ) def get_view_contents(self): - return self.view.substr( sublime.Region( 0, self.view.size() - 1 ) ) + return self.view.substr( sublime.Region( 0, self.view.size() ) ) def test_triple_quotes_comment(self): self.setText( """\ @@ -75,7 +75,7 @@ def test_triple_quotes_wrappting(self): self.view.run_command( "wrap_lines_plus", {"width": 50} ) self.assertEqual( wrap_text( """\ /// This is a doxygen is a doxygen is a doxygen is - /// a doxygen style multiline C++ comment""" ), + /// a doxygen style multiline C++ comment.""" ), self.get_view_contents() ) def test_double_quotes_wrappting(self): @@ -87,7 +87,7 @@ def test_double_quotes_wrappting(self): self.view.run_command( "wrap_lines_plus", {"width": 50} ) self.assertEqual( wrap_text( """\ // This is a doxygen is a doxygen is a doxygen is - // a doxygen style multiline C++ comment""" ), + // a doxygen style multiline C++ comment.""" ), self.get_view_contents() ) def test_double_quotes_wrappting_without_leading_whitespace(self): @@ -99,7 +99,7 @@ def test_double_quotes_wrappting_without_leading_whitespace(self): self.view.run_command( "wrap_lines_plus", {"width": 50} ) self.assertEqual( wrap_text( """\ //This is a doxygen is a doxygen is a doxygen is a - //doxygen style multiline C++ comment""" ), + //doxygen style multiline C++ comment.""" ), self.get_view_contents() ) def test_triple_quotes_wrappting_without_leading_whitespace(self): @@ -111,6 +111,24 @@ def test_triple_quotes_wrappting_without_leading_whitespace(self): self.view.run_command( "wrap_lines_plus", {"width": 50} ) self.assertEqual( wrap_text( """\ ///This is a doxygen is a doxygen is a doxygen is - ///a doxygen style multiline C++ comment""" ), + ///a doxygen style multiline C++ comment.""" ), self.get_view_contents() ) + def test_markdown_triple_quotes_line_start(self): + self.setText( """\ + 1. Although if you prefer, you can provide a menu entry forMyBrandNewChannel` directory: + ```javascript + [ + ] + ```""" ) + + self.view.run_command( "wrap_lines_plus", {"width": 60} ) + self.assertEqual( wrap_text( """\ + 1. Although if you prefer, you can provide a menu entry + forMyBrandNewChannel` directory: + ```javascript + [ + ] + ```""" ), + self.get_view_contents() ) + From 97c9a423a38f9c557cf5f4356bfd17999d8293c5 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 8 Dec 2017 15:26:14 -0200 Subject: [PATCH 068/160] Fixes https://github.com/evandrocoan/ITE/issues/61 badly wraps ``` inside list --- tests/text_extraction_unit_tests.py | 8 +++----- wrap_plus.py | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/text_extraction_unit_tests.py b/tests/text_extraction_unit_tests.py index aab3674..882213a 100644 --- a/tests/text_extraction_unit_tests.py +++ b/tests/text_extraction_unit_tests.py @@ -122,13 +122,11 @@ def test_markdown_triple_quotes_line_start(self): ] ```""" ) - self.view.run_command( "wrap_lines_plus", {"width": 60} ) + self.view.run_command( "wrap_lines_plus", {"width": 100} ) self.assertEqual( wrap_text( """\ - 1. Although if you prefer, you can provide a menu entry - forMyBrandNewChannel` directory: + 1. Although if you prefer, you can provide a menu entry forMyBrandNewChannel` directory: ```javascript [ ] - ```""" ), - self.get_view_contents() ) + ```""" ), self.get_view_contents() ) diff --git a/wrap_plus.py b/wrap_plus.py index 05f592f..81b7425 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -241,7 +241,7 @@ def OR(*args): def CONCAT(*args): return '(?:' + ''.join(args) + ')' -blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*)$|(?:.*"""\\?)') +blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*(?:````?.*)?)$|(?:.*"""\\?)') next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) whitespace_character = (" ", "\t") @@ -1271,7 +1271,7 @@ def run_tests(): unit_tests_to_run = \ [ # "test_semantic_line_wrap_ending_with_comma_list", - # "test_is_command_separated_list_5_items", + # "test_markdown_triple_quotes_line_start", # "test_is_command_separated_list_4_items", # "test_is_command_separated_list_3_items", # "test_is_command_separated_list_2_items", From a745948610bc09fb0abc075775db6215f8e234eb Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 19 Dec 2017 16:29:55 -0200 Subject: [PATCH 069/160] Added support to force classic or semantic line wrap commands on WrapPlus.sublime-commands and deprecated the old widths default commands values. --- WrapPlus.sublime-commands | 13 ++++++------- wrap_plus.py | 23 +++++++++++++++++++---- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/WrapPlus.sublime-commands b/WrapPlus.sublime-commands index 2ce4f3f..7967071 100644 --- a/WrapPlus.sublime-commands +++ b/WrapPlus.sublime-commands @@ -1,10 +1,9 @@ [ - { "caption": "Wrap Plus: Wrap Lines","command": "wrap_lines_plus" }, - { "caption": "Wrap Plus: Wrap Lines at ... chars", "command": "wrap_lines_enhancement_ask" }, + { "caption": "Wrap Plus: Wrap Lines", "command": "wrap_lines_plus" }, + { "caption": "Wrap Plus: Force Classic Line Wrap", "command": "wrap_lines_plus", "args": { "line_wrap_type": "classic" } }, + { "caption": "Wrap Plus: Force Semantic Line Wrap", "command": "wrap_lines_plus", "args": { "line_wrap_type": "semantic" } }, - { "caption": "Wrap Plus: Wrap Lines at 65 chars", "command": "wrap_lines_plus", "args": { "width": 65 } }, - { "caption": "Wrap Plus: Wrap Lines at 70 chars", "command": "wrap_lines_plus", "args": { "width": 70 } }, - { "caption": "Wrap Plus: Wrap Lines at 72 chars", "command": "wrap_lines_plus", "args": { "width": 72 } }, - { "caption": "Wrap Plus: Wrap Lines at 80 chars", "command": "wrap_lines_plus", "args": { "width": 80 } }, - { "caption": "Wrap Plus: Wrap Lines at 100 chars", "command": "wrap_lines_plus", "args": { "width": 100 } }, + { "caption": "Wrap Plus: Wrap Lines (ask)", "command": "wrap_lines_enhancement_ask" }, + { "caption": "Wrap Plus: Force Classic Line Wrap (ask)", "command": "wrap_lines_enhancement_ask", "args": { "line_wrap_type": "classic" } }, + { "caption": "Wrap Plus: Force Semantic Line Wrap (ask)", "command": "wrap_lines_enhancement_ask", "args": { "line_wrap_type": "semantic" } }, ] diff --git a/wrap_plus.py b/wrap_plus.py index 81b7425..e0a8bc0 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -671,7 +671,20 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): required_comment_prefix+subsequent_indent, new_lines) - def run(self, edit, width=0): + def get_semantic_line_wrap_setting(self, view_settings, line_wrap_type): + is_semantic_line_wrap = view_settings.get( 'WrapPlus.semantic_line_wrap', False ) + + if line_wrap_type: + + if line_wrap_type == "semantic": + is_semantic_line_wrap = True + + if line_wrap_type == "classic": + is_semantic_line_wrap = False + + return is_semantic_line_wrap + + def run(self, edit, width=0, line_wrap_type=None): debug_start(self.view.settings().get('WrapPlus.debug', False)) debug('\n\n#########################################################################') @@ -714,7 +727,7 @@ def run(self, edit, width=0): disable_line_wrapping_by_maximum_width = True # print( "minimum_line_size_percent: " + str( minimum_line_size_percent ) ) - if view_settings.get( 'WrapPlus.semantic_line_wrap', False ): + if self.get_semantic_line_wrap_setting( view_settings, line_wrap_type ): def line_wrapper_type(): text = self.semantic_line_wrap( paragraph_lines, initial_indent, subsequent_indent, @@ -1237,7 +1250,9 @@ def print_text_replacements(self, text, selection): class WrapLinesEnhancementAskCommand(sublime_plugin.TextCommand): - def run(self, edit, **kwargs): + def run(self, edit, line_wrap_type=None): + self.line_wrap_type = line_wrap_type + sublime.active_window().show_input_panel( 'Provide wrapping width:', str( last_used_width ), self.input_package, None, None @@ -1247,7 +1262,7 @@ def input_package(self, width): global last_used_width last_used_width = width - self.view.run_command( 'wrap_lines_plus', { 'width': int( width ) } ) + self.view.run_command( 'wrap_lines_plus', { 'width': int( width ), "line_wrap_type": self.line_wrap_type } ) def run_tests(): From 95c120bc449065ae955300b108642f28a0df461a Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 22 Dec 2017 14:45:05 -0200 Subject: [PATCH 070/160] Isolated semantic line feed settings on Base File.sublime-settings at the end of the file. --- Base File.sublime-settings | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 983cd50..8ff50e6 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -7,11 +7,21 @@ "WrapPlus.break_on_hyphens": false, // Control the cursor behavior while wrapping the text. It accepts the following: - // // "cursor_below", will move the cursor/caret to the end the the wrapped text // "cursor_stay", will `attempt` to keep the cursor/caret on its original position "WrapPlus.after_wrap": "cursor_stay", + // Determines whether or not line endings are included in the line size: + // - true: Always included. + // - false: Never included. + // - "auto": Included only if Sublime's "word_wrap" is enabled (View -> + // Word Wrap) and Sublime's wrap column is not 0 (View -> Word Wrap + // Column -> Automatic). + "WrapPlus.include_line_endings": "auto", + + // Set the wrap column, overriding Sublime's "wrap_width" if not 0. + // "WrapPlus.wrap_width": 78 + // If true, the semantic linewrap also know as semantic linefeed will be used. // See the following address for more descriptions: // http://rhodesmill.org/brandon/2012/one-sentence-per-line/ @@ -70,15 +80,4 @@ // * If the setting `WrapPlus.balance_characters_between_line_wraps` is enabled, // this setting will be ignored. "WrapPlus.semantic_disable_line_wrapping_by_maximum_width": false, - - // Determines whether or not line endings are included in the line size: - // - true: Always included. - // - false: Never included. - // - "auto": Included only if Sublime's "word_wrap" is enabled (View -> - // Word Wrap) and Sublime's wrap column is not 0 (View -> Word Wrap - // Column -> Automatic). - "WrapPlus.include_line_endings": "auto" - - // Set the wrap column, overriding Sublime's "wrap_width" if not 0. - // "WrapPlus.wrap_width": 78 } From 156eb45b8d8c5351ffd20c69033b18104c37f477 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 22 Dec 2017 15:07:36 -0200 Subject: [PATCH 071/160] Created the setting semantic_wrap_extension_percent to set the percentage of the current line wrapping limit to be applied when performing the semantic line feed wrapping. For example, if you line wrapping is set to `100` characters and this setting is set to `1.6`, the line wrapping limit will be 160 characters when performing the semantic linefeed wrapping. --- Base File.sublime-settings | 9 +++++++++ wrap_plus.py | 10 ++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 8ff50e6..3f26b18 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -52,6 +52,15 @@ // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. "WrapPlus.semantic_minimum_line_size_percent": 0.0, + // Set the percentage of the current line wrapping limit to be applied when + // performing the semantic line feed wrapping. For example, if you line + // wrapping is set to `100` characters and this setting is set to `1.6`, the + // line wrapping limit will be 160 characters when performing the semantic + // linefeed wrapping. + // + // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. + "WrapPlus.semantic_wrap_extension_percent": 1.6, + // When wrapping lines, it will consider they to be a list of words if between // two sequential commas is find at the maximum these number of words. // diff --git a/wrap_plus.py b/wrap_plus.py index e0a8bc0..9c70186 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -711,6 +711,7 @@ def run(self, edit, width=0, line_wrap_type=None): break_long_words = view_settings.get('WrapPlus.break_long_words', True) break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', True) + wrap_extension_percent = view_settings.get('WrapPlus.semantic_wrap_extension_percent', 1.0) minimum_line_size_percent = view_settings.get('WrapPlus.semantic_minimum_line_size_percent', 0.2) balance_characters_between_line_wraps = view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.semantic_disable_line_wrapping_by_maximum_width', False) @@ -718,16 +719,13 @@ def run(self, edit, width=0, line_wrap_type=None): self.maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 self.maximum_items_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_items_in_comma_separated_list', 3) + 1 - wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) - wrapper.width = self._width - wrapper.expand_tabs = False - if balance_characters_between_line_wraps: # minimum_line_size_percent = 0.0 disable_line_wrapping_by_maximum_width = True # print( "minimum_line_size_percent: " + str( minimum_line_size_percent ) ) if self.get_semantic_line_wrap_setting( view_settings, line_wrap_type ): + self._width *= wrap_extension_percent def line_wrapper_type(): text = self.semantic_line_wrap( paragraph_lines, initial_indent, subsequent_indent, @@ -745,6 +743,10 @@ def line_wrapper_type(): def line_wrapper_type(): return self.classic_wrap_text(wrapper, paragraph_lines, initial_indent, subsequent_indent) + wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) + wrapper.width = self._width + wrapper.expand_tabs = False + # print( "self._width: " + str( self._width ) ) if paragraphs: # Use view selections to handle shifts from the replace() command. From dba8e807574f1d0a3680ace5585e42b11dd5232d Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 5 Jan 2018 09:04:30 -0200 Subject: [PATCH 072/160] Created .travis.yml --- .travis.yml | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5a9a3db --- /dev/null +++ b/.travis.yml @@ -0,0 +1,55 @@ +env: + global: + - PACKAGE="WrapPlus" # Package name + - SUBLIME_TEXT_VERSION="3" + # use UNITTESTING_TAG to specific tag of UnitTesting + # - UNITTESTING_TAG="master" + +# mutliple os matrix +# https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages) +matrix: + include: + - os: linux + language: python + python: 3.3 + - os: osx + language: generic + + +before_install: + - curl -OL https://raw.githubusercontent.com/SublimeText/UnitTesting/master/sbin/travis.sh + # enable gui, see https://docs.travis-ci.com/user/gui-and-headless-browsers + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then + export DISPLAY=:99.0; + sh -e /etc/init.d/xvfb start; + fi + +install: + # bootstrap the testing environment + - sh travis.sh bootstrap + # install Package Control and package denepdencies + # - sh travis.sh install_package_control + +script: + # run tests with test coverage report + - sh travis.sh run_tests --coverage + # testing syntax_test files + # - sh travis.sh run_syntax_tests + +after_success: + # remove the following if `coveralls` is not needed + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then + brew update; + brew install python3; + pip3 install python-coveralls; + pip3 install codecov; + fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then + pip install python-coveralls; + pip install codecov; + fi + - coveralls + - codecov + +notifications: + email: false From 933ec0a1de41e4241bc7c64d9906469b19fc608d Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 5 Jan 2018 09:28:28 -0200 Subject: [PATCH 073/160] Fixed Unit Tests not running after renaming the package from Wrap Plus to WrapPlus --- tests/semantic_linefeed_manual_tests.py | 6 +++++- tests/semantic_linefeed_unit_tests.py | 6 +++++- tests/text_extraction_unit_tests.py | 5 ++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index 5ba18eb..a895219 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -1,12 +1,16 @@ +import os import sys import textwrap import unittest -wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] +CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) +CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] + +wrap_plus_module = sys.modules[CURRENT_PACKAGE_NAME + ".wrap_plus"] def run_manual_tests(): diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 1fa6f0b..64feb45 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -1,11 +1,15 @@ +import os import sys import textwrap import unittest -wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] +CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) +CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] + +wrap_plus_module = sys.modules[CURRENT_PACKAGE_NAME + ".wrap_plus"] class LineBalancingUnitTests(unittest.TestCase): diff --git a/tests/text_extraction_unit_tests.py b/tests/text_extraction_unit_tests.py index 882213a..57d0bed 100644 --- a/tests/text_extraction_unit_tests.py +++ b/tests/text_extraction_unit_tests.py @@ -1,5 +1,6 @@ +import os import sys import sublime @@ -8,8 +9,10 @@ import textwrap import unittest +CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) +CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] -wrap_plus_module = sys.modules["Wrap Plus.wrap_plus"] +wrap_plus_module = sys.modules[CURRENT_PACKAGE_NAME + ".wrap_plus"] def wrap_text(text): From 3e18ea8f37f753f7858e929d075f9deceeda7cc4 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 5 Jan 2018 09:42:40 -0200 Subject: [PATCH 074/160] Added Travis badge to README.md and removed the settings from it as they are already present on the configuration file, and keep both texts synced is nonsense. --- README.md | 77 +++++++++++-------------------------------------------- 1 file changed, 15 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index d973758..c7d01f9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ -# Sublime Wrap Plus # +# Sublime Wrap Plus [![Build Status](https://travis-ci.org/evandrocoan/WrapPlus.svg?branch=master)](https://travis-ci.org/evandrocoan/WrapPlus) + Enhanced "wrap lines" command for Sublime Text 2 or 3. This is for the *manual* hard line wrap command (AltQ in Windows and Linux, CommandAltQ in OS X). It does not affect the automatic soft line wrapping. -## Downloading ## +## Downloading The best way to download and install Sublime Wrap Plus is to use the [Package Control](https://packagecontrol.io) plugin. If you do not already have it installed, it's really the best way to manage your packages. For users new to the package manager: @@ -25,7 +26,7 @@ git clone git://github.com/ehuss/Sublime-Wrap-Plus.git and place it in your Packages directory, which can be found by selecting **`Preferences → Browse Packages...`**. -## Configuring ## +## Configuring No need to configure anything. By default it uses the default keystroke for wrap lines: * Windows/Linux: AltQ @@ -43,57 +44,9 @@ If you want to, you can add keystrokes that use specific wrap sizes: { "keys": ["alt+q", "7"], "command": "wrap_lines_plus", "args": {"width": 70}} ``` -There are a few settings you can tweak if you so desire. You can set them in **`Preferences → Settings — User`**. They are: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameDefaultDescription
"wrap_width"0The maximum line width. If 0, defaults to the first ruler, or 78. Also set via View → Word Wrap Column.
"WrapPlus.wrap_width"If set, this will override Sublime's "wrap_width" setting. You might want to use this if you have automatic soft word wrapping enabled, but want hard wraps at a different width. -
"word_wrap""auto"This disables horizontal scrolling (*soft* or *automatic* word wrapping). May be true, false, or "auto" where it will be disabled for source code. Also toggled via View → Word Wrap.
"WrapPlus.break_long_words"trueA single word that is longer than your wrap column will be forced to be break at the wrap column.
"WrapPlus.semantic_line_wrap"falseIf true, the semantic linewrap also know as semantic linefeed will be used. See the following address for more descriptions: http://rhodesmill.org/brandon/2012/one-sentence-per-line/
"WrapPlus.break_on_hyphens"trueWhether or not to break lines on hyphens.
"WrapPlus.include_line_endings""auto"Determines whether or not line endings are included in the line size: -
    -
  • true: Always included. -
  • false: Never included. -
  • "auto": Included only if Sublime's "word_wrap" is enabled (View → Word Wrap) and Sublime's wrap column is not 0 (View → Word Wrap Column → Automatic). -
-
- -### Advanced Configuration ### +There are a few settings you can tweak if you so desire. You can set them in **`Preferences → Settings — User`**. + +### Advanced Configuration Sublime supports placing configuration options in a variety of places. You can put any of these settings in one of the following files (last file wins): 1. Packages/User/Preferences.sublime-settings @@ -101,10 +54,10 @@ Sublime supports placing configuration options in a variety of places. You can 3. Packages/User/***SyntaxName***.sublime-settings 4. Packages/User/Distraction Free.sublime-settings -## Using ## +## Using Whenever the cursor is anywhere within a paragraph, hitting the Wrap Plus keystroke will cause it to try to discover where the paragraph starts and where it ends. It will then wrap all of those lines according to the wrap width you currently have set (**`View → Word Wrap Column`**). -### Lists ### +### Lists It handles a variety of lists, like bulleted lists or numbered lists. They should line up nicely: ``` @@ -121,7 +74,7 @@ It handles a variety of lists, like bulleted lists or numbered lists. They shoul beef speck pig kielbasa short loin. ``` -### Subsequent Indents ### +### Subsequent Indents Lines with subsequent indents should maintain their indent: ```rst @@ -130,7 +83,7 @@ Lines with subsequent indents should maintain their indent: lollipop I love cotton brownie. ``` -### Comment Lines ### +### Comment Lines In a source code file, it should transparently handle single-line comment characters, like: @@ -164,7 +117,7 @@ In addition, JavaDoc or JsDoc style documentation should work, too: */ ``` -### Python Strings ### +### Python Strings When wrapping inside a Python triple quoted string, wrapping will be constrained to the inside of the string. That way, doc strings won't get wrapped with function definitions: @@ -175,7 +128,7 @@ def foo(): """ ``` -### Email Quotes ### +### Email Quotes Lines with email-style quoting should be handled. Nested quotes should be treated as separate paragraphs. ``` @@ -185,10 +138,10 @@ Lines with email-style quoting should be handled. Nested quotes should be treat > And continuing with a third paragraph. ``` -### Selection Wrapping ### +### Selection Wrapping If you select a range of characters, *only* the lines that are selected will be wrapped (the stock Sublime wrap lines extends the selection to what it thinks is a paragraph). I find this behavior preferable to give me more control. -## Epilogue ## +## Epilogue Wrap Plus handles a lot of situations that the stock Sublime word wrapper doesn't handle, but it's likely there are many situations where it doesn't work quite right. If you come across a problem, the immediate solution is to manually select the lines you want to wrap (this will constrain wrapping to just those lines). If you'd like, feel free to post an [issue](https://github.com/ehuss/Sublime-Wrap-Plus/issues) on the Github page. From 7d2d2ee4354512031b1af9db275a2c02f67c8029 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 5 Jan 2018 13:13:27 -0200 Subject: [PATCH 075/160] Created the appveyor.yml and its badge on README.md --- README.md | 5 ++++- appveyor.yml | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 appveyor.yml diff --git a/README.md b/README.md index c7d01f9..07d9a71 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -# Sublime Wrap Plus [![Build Status](https://travis-ci.org/evandrocoan/WrapPlus.svg?branch=master)](https://travis-ci.org/evandrocoan/WrapPlus) +# Sublime Wrap Plus + +[![Build Status](https://travis-ci.org/evandrocoan/WrapPlus.svg?branch=master)](https://travis-ci.org/evandrocoan/WrapPlus) + Enhanced "wrap lines" command for Sublime Text 2 or 3. This is for the *manual* hard line wrap command (AltQ in Windows and Linux, CommandAltQ in OS X). It does not affect the automatic soft line wrapping. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..c0ef699 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,23 @@ +environment: + # The package name + PACKAGE: "WrapPlus" + SUBLIME_TEXT_VERSION : "3" + +install: + - ps: appveyor DownloadFile "https://raw.githubusercontent.com/SublimeText/UnitTesting/master/sbin/appveyor.ps1" + - ps: .\appveyor.ps1 "bootstrap" -verbose + # install Package Control + # - ps: .\appveyor.ps1 "install_package_control" -verbose + +build: off + +test_script: + + # run tests with test coverage report + - ps: .\appveyor.ps1 "run_tests" -coverage -verbose + +after_test: + - "SET PYTHON=C:\Python33" + - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" + - pip install codecov + - codecov From 41922daff7be5236db19a00ce474a2a9b2e62321 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 5 Jan 2018 15:33:15 -0200 Subject: [PATCH 076/160] Added the AppVeyor badge into README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 07d9a71..4026d45 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Sublime Wrap Plus [![Build Status](https://travis-ci.org/evandrocoan/WrapPlus.svg?branch=master)](https://travis-ci.org/evandrocoan/WrapPlus) +[![Build status](https://ci.appveyor.com/api/projects/status/464j3oiwijfutl8t/branch/master?svg=true)](https://ci.appveyor.com/project/evandrocoan/wrapplus/branch/master) Enhanced "wrap lines" command for Sublime Text 2 or 3. This is for the *manual* hard line wrap command (AltQ in Windows and Linux, CommandAltQ in OS X). It does not affect the automatic soft line wrapping. From 9049a02134a911d70108466be78fc36c0ed4b8fe Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 5 Jan 2018 16:16:55 -0200 Subject: [PATCH 077/160] Added Codecov and Coveralls badge on README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4026d45..37de5e1 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ [![Build Status](https://travis-ci.org/evandrocoan/WrapPlus.svg?branch=master)](https://travis-ci.org/evandrocoan/WrapPlus) [![Build status](https://ci.appveyor.com/api/projects/status/464j3oiwijfutl8t/branch/master?svg=true)](https://ci.appveyor.com/project/evandrocoan/wrapplus/branch/master) +[![codecov](https://codecov.io/gh/evandrocoan/WrapPlus/branch/master/graph/badge.svg)](https://codecov.io/gh/evandrocoan/WrapPlus) +[![Coverage Status](https://coveralls.io/repos/github/evandrocoan/WrapPlus/badge.svg?branch=master)](https://coveralls.io/github/evandrocoan/WrapPlus?branch=master) Enhanced "wrap lines" command for Sublime Text 2 or 3. This is for the *manual* hard line wrap command (AltQ in Windows and Linux, CommandAltQ in OS X). It does not affect the automatic soft line wrapping. From 296515af5e4f3e49bfcad0676fc876ce7783381a Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 6 Jan 2018 14:59:31 -0200 Subject: [PATCH 078/160] Renamed CURRENT_DIRECTORY/PACKAGE_NAME to ROOT_DIRECTORY/PACKAGE --- tests/semantic_linefeed_manual_tests.py | 6 ++---- tests/semantic_linefeed_unit_tests.py | 5 ++--- tests/text_extraction_unit_tests.py | 5 ++--- tests/unit_tests_runner.py | 4 ++-- wrap_plus.py | 4 ++-- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/semantic_linefeed_manual_tests.py index a895219..fee967d 100644 --- a/tests/semantic_linefeed_manual_tests.py +++ b/tests/semantic_linefeed_manual_tests.py @@ -6,10 +6,8 @@ import textwrap import unittest - -CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) -CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] - +PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) +CURRENT_PACKAGE_NAME = os.path.basename( PACKAGE_ROOT_DIRECTORY ).rsplit('.', 1)[0] wrap_plus_module = sys.modules[CURRENT_PACKAGE_NAME + ".wrap_plus"] diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/semantic_linefeed_unit_tests.py index 64feb45..bb0820d 100644 --- a/tests/semantic_linefeed_unit_tests.py +++ b/tests/semantic_linefeed_unit_tests.py @@ -6,9 +6,8 @@ import textwrap import unittest -CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) -CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] - +PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) +CURRENT_PACKAGE_NAME = os.path.basename( PACKAGE_ROOT_DIRECTORY ).rsplit('.', 1)[0] wrap_plus_module = sys.modules[CURRENT_PACKAGE_NAME + ".wrap_plus"] diff --git a/tests/text_extraction_unit_tests.py b/tests/text_extraction_unit_tests.py index 57d0bed..1c7cac5 100644 --- a/tests/text_extraction_unit_tests.py +++ b/tests/text_extraction_unit_tests.py @@ -9,9 +9,8 @@ import textwrap import unittest -CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) -CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] - +PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) +CURRENT_PACKAGE_NAME = os.path.basename( PACKAGE_ROOT_DIRECTORY ).rsplit('.', 1)[0] wrap_plus_module = sys.modules[CURRENT_PACKAGE_NAME + ".wrap_plus"] diff --git a/tests/unit_tests_runner.py b/tests/unit_tests_runner.py index f3eee72..f577def 100644 --- a/tests/unit_tests_runner.py +++ b/tests/unit_tests_runner.py @@ -4,8 +4,8 @@ import sys import unittest -CURRENT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) -CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] +PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.dirname( os.path.realpath( __file__ ) ) ) +CURRENT_PACKAGE_NAME = os.path.basename( PACKAGE_ROOT_DIRECTORY ).rsplit('.', 1)[0] def run_unit_tests(unit_tests_to_run=[]): diff --git a/wrap_plus.py b/wrap_plus.py index 9c70186..ea09b9f 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1272,8 +1272,8 @@ def run_tests(): How do I unload (reload) a Python module? https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module """ - CURRENT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) ) - CURRENT_PACKAGE_NAME = os.path.basename( CURRENT_DIRECTORY ).rsplit('.', 1)[0] + PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) ) + CURRENT_PACKAGE_NAME = os.path.basename( PACKAGE_ROOT_DIRECTORY ).rsplit('.', 1)[0] print( "\n\n" ) sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.unit_tests_runner" ) From 5d392422c0a54ae3bcac68f7b6a9a0b69eeeb6f8 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 13 Jan 2018 22:09:22 -0200 Subject: [PATCH 079/160] Replaced the AppVeyor codified URL by the pure repository name on README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37de5e1..8ef9aec 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Sublime Wrap Plus [![Build Status](https://travis-ci.org/evandrocoan/WrapPlus.svg?branch=master)](https://travis-ci.org/evandrocoan/WrapPlus) -[![Build status](https://ci.appveyor.com/api/projects/status/464j3oiwijfutl8t/branch/master?svg=true)](https://ci.appveyor.com/project/evandrocoan/wrapplus/branch/master) +[![Build status](https://ci.appveyor.com/api/projects/status/github/evandrocoan/WrapPlus?branch=master&svg=true)](https://ci.appveyor.com/project/evandrocoan/WrapPlus/branch/master) [![codecov](https://codecov.io/gh/evandrocoan/WrapPlus/branch/master/graph/badge.svg)](https://codecov.io/gh/evandrocoan/WrapPlus) [![Coverage Status](https://coveralls.io/repos/github/evandrocoan/WrapPlus/badge.svg?branch=master)](https://coveralls.io/github/evandrocoan/WrapPlus?branch=master) From d102089c391e5af980d548126e954a4dd6ef879c Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 14 Jan 2018 20:38:48 -0200 Subject: [PATCH 080/160] Created the latest version badge on README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ef9aec..94b48f2 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Build status](https://ci.appveyor.com/api/projects/status/github/evandrocoan/WrapPlus?branch=master&svg=true)](https://ci.appveyor.com/project/evandrocoan/WrapPlus/branch/master) [![codecov](https://codecov.io/gh/evandrocoan/WrapPlus/branch/master/graph/badge.svg)](https://codecov.io/gh/evandrocoan/WrapPlus) [![Coverage Status](https://coveralls.io/repos/github/evandrocoan/WrapPlus/badge.svg?branch=master)](https://coveralls.io/github/evandrocoan/WrapPlus?branch=master) +[![Latest Release](https://img.shields.io/github/tag/evandrocoan/WrapPlus.svg?label=version)](https://github.com/evandrocoan/WrapPlus/releases) Enhanced "wrap lines" command for Sublime Text 2 or 3. This is for the *manual* hard line wrap command (AltQ in Windows and Linux, CommandAltQ in OS X). It does not affect the automatic soft line wrapping. @@ -168,4 +169,3 @@ the file. The results are going to be displayed on the `Sublime Text Console`. ## License See the `LICENSE.txt` file under this repository. - From 20408ad6357d855991ad652480fcdfc0a5cf2fec Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 14 Jan 2018 21:16:31 -0200 Subject: [PATCH 081/160] Updated .travis.yml and appveyor.yml to always run the Unit Tests issue: Not uploading coverage reports when there are tests failures/errors https://github.com/SublimeText/UnitTesting/issues/77 --- .travis.yml | 26 +++++++++++++------------- appveyor.yml | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5a9a3db..34239fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,9 +15,18 @@ matrix: - os: osx language: generic - before_install: - curl -OL https://raw.githubusercontent.com/SublimeText/UnitTesting/master/sbin/travis.sh + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then + brew update; + brew install python3; + pip3 install python-coveralls; + pip3 install codecov; + fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then + pip install python-coveralls; + pip install codecov; + fi # enable gui, see https://docs.travis-ci.com/user/gui-and-headless-browsers - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export DISPLAY=:99.0; @@ -35,21 +44,12 @@ script: - sh travis.sh run_tests --coverage # testing syntax_test files # - sh travis.sh run_syntax_tests + - coveralls + - codecov after_success: # remove the following if `coveralls` is not needed - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then - brew update; - brew install python3; - pip3 install python-coveralls; - pip3 install codecov; - fi - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then - pip install python-coveralls; - pip install codecov; - fi - - coveralls - - codecov + - echo notifications: email: false diff --git a/appveyor.yml b/appveyor.yml index c0ef699..16f2a12 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,11 +12,11 @@ install: build: off test_script: - # run tests with test coverage report - ps: .\appveyor.ps1 "run_tests" -coverage -verbose + - echo -after_test: +on_finish: - "SET PYTHON=C:\Python33" - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - pip install codecov From 3361e713abb81c4fc93125742eacba80ddc4cda3 Mon Sep 17 00:00:00 2001 From: The Codacy Badger Date: Sun, 14 Jan 2018 23:38:47 +0000 Subject: [PATCH 082/160] Add Codacy badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 94b48f2..4ec5d55 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Sublime Wrap Plus +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/9191d17b91814f8caf17c9e537a22904)](https://www.codacy.com/app/evandrocoan/WrapPlus?utm_source=github.com&utm_medium=referral&utm_content=evandrocoan/WrapPlus&utm_campaign=badger) [![Build Status](https://travis-ci.org/evandrocoan/WrapPlus.svg?branch=master)](https://travis-ci.org/evandrocoan/WrapPlus) [![Build status](https://ci.appveyor.com/api/projects/status/github/evandrocoan/WrapPlus?branch=master&svg=true)](https://ci.appveyor.com/project/evandrocoan/WrapPlus/branch/master) [![codecov](https://codecov.io/gh/evandrocoan/WrapPlus/branch/master/graph/badge.svg)](https://codecov.io/gh/evandrocoan/WrapPlus) From 7de10b7d1fe07cd5c19d2b4821b7e235139a4c5c Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 14 Jan 2018 21:58:37 -0200 Subject: [PATCH 083/160] Attempted to setup Codacy on .travis.yml and appveyor.yml --- .travis.yml | 22 ++++++++++++++++++++-- appveyor.yml | 8 ++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34239fb..212fbcd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ + env: global: - PACKAGE="WrapPlus" # Package name @@ -5,6 +6,7 @@ env: # use UNITTESTING_TAG to specific tag of UnitTesting # - UNITTESTING_TAG="master" + # mutliple os matrix # https://docs.travis-ci.com/user/multi-os/#Python-example-(unsupported-languages) matrix: @@ -12,40 +14,56 @@ matrix: - os: linux language: python python: 3.3 + - os: osx language: generic + before_install: - curl -OL https://raw.githubusercontent.com/SublimeText/UnitTesting/master/sbin/travis.sh + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install python3; pip3 install python-coveralls; pip3 install codecov; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then pip install python-coveralls; pip install codecov; + pip install coverage codacy-coverage fi + # enable gui, see https://docs.travis-ci.com/user/gui-and-headless-browsers - if [ "$TRAVIS_OS_NAME" == "linux" ]; then export DISPLAY=:99.0; sh -e /etc/init.d/xvfb start; fi + install: # bootstrap the testing environment - sh travis.sh bootstrap + # install Package Control and package denepdencies # - sh travis.sh install_package_control + script: # run tests with test coverage report - sh travis.sh run_tests --coverage + # testing syntax_test files # - sh travis.sh run_syntax_tests - - coveralls - - codecov + + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then + coveralls; + codecov; + coverage xml -o coverage.xml; + python-codacy-coverage; + fi + after_success: # remove the following if `coveralls` is not needed diff --git a/appveyor.yml b/appveyor.yml index 16f2a12..28a9c7f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,23 +1,31 @@ + environment: # The package name PACKAGE: "WrapPlus" SUBLIME_TEXT_VERSION : "3" + install: - ps: appveyor DownloadFile "https://raw.githubusercontent.com/SublimeText/UnitTesting/master/sbin/appveyor.ps1" - ps: .\appveyor.ps1 "bootstrap" -verbose + - ps: pip install coverage codacy-coverage # install Package Control # - ps: .\appveyor.ps1 "install_package_control" -verbose + build: off + test_script: # run tests with test coverage report - ps: .\appveyor.ps1 "run_tests" -coverage -verbose - echo + on_finish: - "SET PYTHON=C:\Python33" - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - pip install codecov - codecov + - coverage xml -o coverage.xml + - python-codacy-coverage From 9a9201fdac7ee1d98205e5396c41b842ac51ec12 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 14 Jan 2018 21:58:37 -0200 Subject: [PATCH 084/160] Attempted to setup Codacy on .travis.yml and appveyor.yml --- README.md | 2 +- wrap_plus.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 4ec5d55..806bd25 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Sublime Wrap Plus -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/9191d17b91814f8caf17c9e537a22904)](https://www.codacy.com/app/evandrocoan/WrapPlus?utm_source=github.com&utm_medium=referral&utm_content=evandrocoan/WrapPlus&utm_campaign=badger) [![Build Status](https://travis-ci.org/evandrocoan/WrapPlus.svg?branch=master)](https://travis-ci.org/evandrocoan/WrapPlus) [![Build status](https://ci.appveyor.com/api/projects/status/github/evandrocoan/WrapPlus?branch=master&svg=true)](https://ci.appveyor.com/project/evandrocoan/WrapPlus/branch/master) [![codecov](https://codecov.io/gh/evandrocoan/WrapPlus/branch/master/graph/badge.svg)](https://codecov.io/gh/evandrocoan/WrapPlus) [![Coverage Status](https://coveralls.io/repos/github/evandrocoan/WrapPlus/badge.svg?branch=master)](https://coveralls.io/github/evandrocoan/WrapPlus?branch=master) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/9191d17b91814f8caf17c9e537a22904)](https://www.codacy.com/app/evandrocoan/WrapPlus?utm_source=github.com&utm_medium=referral&utm_content=evandrocoan/WrapPlus&utm_campaign=badger) [![Latest Release](https://img.shields.io/github/tag/evandrocoan/WrapPlus.svg?label=version)](https://github.com/evandrocoan/WrapPlus/releases) diff --git a/wrap_plus.py b/wrap_plus.py index ea09b9f..c7d643e 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1305,4 +1305,3 @@ def plugin_loaded(): """ pass # run_tests() - From d8d6d077f87663b2f7946607d5670468aca60e62 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 15 Jan 2018 18:50:50 -0200 Subject: [PATCH 085/160] Before we dig any deeper into this could you please try the troubleshoot suggested here: https://github.com/codacy/python-codacy-coverage#troubleshoot --- .travis.yml | 1 + appveyor.yml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 66b849e..f3a1550 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,3 +71,4 @@ after_success: notifications: email: false + diff --git a/appveyor.yml b/appveyor.yml index 28a9c7f..a8d56c1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,4 +28,5 @@ on_finish: - pip install codecov - codecov - coverage xml -o coverage.xml - - python-codacy-coverage + - python-codacy-coverage -c $APPVEYOR_REPO_COMMIT -d $APPVEYOR_BUILD_FOLDER -r coverage.xml + From adce2c4da2a1ec23071d7811e0578ac898534ffb Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 23 Jan 2018 13:36:59 -0200 Subject: [PATCH 086/160] Reverted before we dig any deeper into this could you please try the troubleshoot suggested here: https://github.com/codacy/python-codacy-coverage#troubleshoot And disabled the python-codacy-coverage for appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a8d56c1..c30b387 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,5 +28,5 @@ on_finish: - pip install codecov - codecov - coverage xml -o coverage.xml - - python-codacy-coverage -c $APPVEYOR_REPO_COMMIT -d $APPVEYOR_BUILD_FOLDER -r coverage.xml + - python-codacy-coverage From 5680b39c0b9eebf44397a83341cb314764b446d0 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 25 Jan 2018 21:50:20 -0200 Subject: [PATCH 087/160] Added python --version to appveyor.yml --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index c30b387..995dba3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,6 +27,7 @@ on_finish: - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - pip install codecov - codecov + - python --version - coverage xml -o coverage.xml - python-codacy-coverage From 9b17936af2436d6931a50d4df7cd9f2688c6ab4f Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 25 Jan 2018 22:00:43 -0200 Subject: [PATCH 088/160] Added - echo %PATH% to appveyor.yml --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index 995dba3..796b412 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,6 +28,7 @@ on_finish: - pip install codecov - codecov - python --version + - echo %PATH% - coverage xml -o coverage.xml - python-codacy-coverage From dbf423f2c486b239dc574958d12b7b811fb27b47 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 25 Jan 2018 22:06:10 -0200 Subject: [PATCH 089/160] Double escaped \\ python3.3 path on appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 796b412..330b7ab 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,7 +23,7 @@ test_script: on_finish: - - "SET PYTHON=C:\Python33" + - "SET PYTHON=C:\\Python33" - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - pip install codecov - codecov From f919b67ccca936720ae39409ac321bf7ec93bbcc Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 13 Feb 2018 20:51:42 -0200 Subject: [PATCH 090/160] Enabled by default semantic_balance_characters_between_line_wraps --- Base File.sublime-settings | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Base File.sublime-settings b/Base File.sublime-settings index 3f26b18..9c9729a 100644 --- a/Base File.sublime-settings +++ b/Base File.sublime-settings @@ -39,7 +39,7 @@ // will wrap near its end, // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. - "WrapPlus.semantic_balance_characters_between_line_wraps": false, + "WrapPlus.semantic_balance_characters_between_line_wraps": true, // The minimum of the percentage of the current maximum line width a line can // have. For example, if you `wrap_width` is set to 100, and you set this to `0.2`, @@ -59,7 +59,7 @@ // linefeed wrapping. // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. - "WrapPlus.semantic_wrap_extension_percent": 1.6, + "WrapPlus.semantic_wrap_extension_percent": 1.5, // When wrapping lines, it will consider they to be a list of words if between // two sequential commas is find at the maximum these number of words. From f68089d582d01affebb17685322b55415eab9957 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 8 Mar 2018 12:56:03 -0300 Subject: [PATCH 091/160] Deprecated the run_tests function in favor of the UnitTesting package usage from the Sublime Text command palette: UnitTesting: Run Unit Tests --- wrap_plus.py | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index c7d643e..e83c78d 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1266,42 +1266,3 @@ def input_package(self, width): last_used_width = width self.view.run_command( 'wrap_lines_plus', { 'width': int( width ), "line_wrap_type": self.line_wrap_type } ) - -def run_tests(): - """ - How do I unload (reload) a Python module? - https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module - """ - PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) ) - CURRENT_PACKAGE_NAME = os.path.basename( PACKAGE_ROOT_DIRECTORY ).rsplit('.', 1)[0] - - print( "\n\n" ) - sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.unit_tests_runner" ) - sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.text_extraction_unit_tests" ) - sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.semantic_linefeed_unit_tests" ) - sublime_plugin.reload_plugin( CURRENT_PACKAGE_NAME + ".tests.semantic_linefeed_manual_tests" ) - - from .tests import unit_tests_runner - from .tests import semantic_linefeed_manual_tests - - # Comment all the tests names on this list, to run all Unit Tests - unit_tests_to_run = \ - [ - # "test_semantic_line_wrap_ending_with_comma_list", - # "test_markdown_triple_quotes_line_start", - # "test_is_command_separated_list_4_items", - # "test_is_command_separated_list_3_items", - # "test_is_command_separated_list_2_items", - ] - - unit_tests_runner.run_unit_tests( unit_tests_to_run ) - # semantic_linefeed_manual_tests.run_manual_tests() - - -def plugin_loaded(): - """ - Running single test from unittest.TestCase via command line - https://stackoverflow.com/questions/15971735/running-single-test-from-unittest-testcase-via-command-line - """ - pass - # run_tests() From c74249b371786ea1bd8544cf6214ae5f4b3dbc03 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 7 Apr 2018 10:40:54 -0300 Subject: [PATCH 092/160] Fixed bug with Alt+W on Widget views by changing Whole Word keybind to Alt+Q and allowing all the case conversion keys to work on View Widgets. --- Default (Linux).sublime-keymap | 6 +++++- Default (OSX).sublime-keymap | 6 +++++- Default (Windows).sublime-keymap | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Default (Linux).sublime-keymap b/Default (Linux).sublime-keymap index 7b60e25..69b0011 100644 --- a/Default (Linux).sublime-keymap +++ b/Default (Linux).sublime-keymap @@ -1,3 +1,7 @@ [ - { "keys": ["alt+q"], "command": "wrap_lines_plus" } + { "keys": ["alt+q"], "command": "wrap_lines_plus", "context": + [ + { "key": "setting.is_widget", "operator": "equal", "operand": false } + ] + } ] diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index a488ae9..69b0011 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -1,3 +1,7 @@ [ - { "keys": ["super+alt+q"], "command": "wrap_lines_plus" } + { "keys": ["alt+q"], "command": "wrap_lines_plus", "context": + [ + { "key": "setting.is_widget", "operator": "equal", "operand": false } + ] + } ] diff --git a/Default (Windows).sublime-keymap b/Default (Windows).sublime-keymap index 7b60e25..69b0011 100644 --- a/Default (Windows).sublime-keymap +++ b/Default (Windows).sublime-keymap @@ -1,3 +1,7 @@ [ - { "keys": ["alt+q"], "command": "wrap_lines_plus" } + { "keys": ["alt+q"], "command": "wrap_lines_plus", "context": + [ + { "key": "setting.is_widget", "operator": "equal", "operand": false } + ] + } ] From e59a2f4ab047c405fe9648048d844814541831a5 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 10 Oct 2018 16:14:09 -0300 Subject: [PATCH 093/160] Created a .no-sublime-package for all packages, in attempt to fix evandrocoan/ITE 108 - Expand Region keybind is not working on stable version. --- .no-sublime-package | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .no-sublime-package diff --git a/.no-sublime-package b/.no-sublime-package new file mode 100644 index 0000000..e69de29 From 8e44e6679e1738d28a99a2e001a305ee2b95f4ab Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 10 Oct 2018 22:36:34 -0300 Subject: [PATCH 094/160] Fixed pip: You are using pip version 18.0, however version 18.1 is available, causing the build to fail on appveyor.yml --- .travis.yml | 4 ++-- appveyor.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f3a1550..9807be9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,8 +25,8 @@ before_install: - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install python3; - pip3 install python-coveralls; - pip3 install codecov; + pip3 --disable-pip-version-check install python-coveralls; + pip3 --disable-pip-version-check install codecov; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then diff --git a/appveyor.yml b/appveyor.yml index 330b7ab..1783bff 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ environment: install: - ps: appveyor DownloadFile "https://raw.githubusercontent.com/SublimeText/UnitTesting/master/sbin/appveyor.ps1" - ps: .\appveyor.ps1 "bootstrap" -verbose - - ps: pip install coverage codacy-coverage + - ps: pip install --disable-pip-version-check coverage codacy-coverage # install Package Control # - ps: .\appveyor.ps1 "install_package_control" -verbose @@ -25,7 +25,7 @@ test_script: on_finish: - "SET PYTHON=C:\\Python33" - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - - pip install codecov + - pip install --disable-pip-version-check codecov - codecov - python --version - echo %PATH% From f32fea0e12c2df02bc1867c980f27872fe53328c Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 18 Oct 2018 20:00:01 -0300 Subject: [PATCH 095/160] Set to select all initial text on the input panel opened by wrap_plus.py --- wrap_plus.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index e83c78d..80694a4 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1255,10 +1255,11 @@ class WrapLinesEnhancementAskCommand(sublime_plugin.TextCommand): def run(self, edit, line_wrap_type=None): self.line_wrap_type = line_wrap_type - sublime.active_window().show_input_panel( + view = sublime.active_window().show_input_panel( 'Provide wrapping width:', str( last_used_width ), self.input_package, None, None ) + view.run_command("select_all") def input_package(self, width): global last_used_width From 82625f9650e0d6f9c1cf6894d928c2241c864eee Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 19 Oct 2018 12:32:18 -0300 Subject: [PATCH 096/160] Renamed Base File.sublime-settings to Preferences.sublime-settings fix https://github.com/SublimeText/PackageDev/issues/196 Cannot find settings under the file called `Base File.sublime-settings` --- Base File.sublime-settings => Preferences.sublime-settings | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Base File.sublime-settings => Preferences.sublime-settings (100%) diff --git a/Base File.sublime-settings b/Preferences.sublime-settings similarity index 100% rename from Base File.sublime-settings rename to Preferences.sublime-settings From 54e606f22e661f989e299023d35290a3258711cb Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 8 Dec 2018 12:51:53 -0200 Subject: [PATCH 097/160] Revert "Created a .no-sublime-package for all packages, in attempt to fix" This reverts commit e59a2f4ab047c405fe9648048d844814541831a5. --- .no-sublime-package | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .no-sublime-package diff --git a/.no-sublime-package b/.no-sublime-package deleted file mode 100644 index e69de29..0000000 From 13e745a327a36273fe487ce01e71dd26f93d6d55 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 17 Dec 2018 19:58:12 -0200 Subject: [PATCH 098/160] Fixed unittesting.json not finding all unit tests --- ...inefeed_manual_tests.py => manual_test_semantic_linefeed.py} | 0 ...emantic_linefeed_unit_tests.py => test_semantic_linefeed.py} | 0 tests/{text_extraction_unit_tests.py => text_extraction.py} | 0 unittesting.json | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename tests/{semantic_linefeed_manual_tests.py => manual_test_semantic_linefeed.py} (100%) rename tests/{semantic_linefeed_unit_tests.py => test_semantic_linefeed.py} (100%) rename tests/{text_extraction_unit_tests.py => text_extraction.py} (100%) diff --git a/tests/semantic_linefeed_manual_tests.py b/tests/manual_test_semantic_linefeed.py similarity index 100% rename from tests/semantic_linefeed_manual_tests.py rename to tests/manual_test_semantic_linefeed.py diff --git a/tests/semantic_linefeed_unit_tests.py b/tests/test_semantic_linefeed.py similarity index 100% rename from tests/semantic_linefeed_unit_tests.py rename to tests/test_semantic_linefeed.py diff --git a/tests/text_extraction_unit_tests.py b/tests/text_extraction.py similarity index 100% rename from tests/text_extraction_unit_tests.py rename to tests/text_extraction.py diff --git a/unittesting.json b/unittesting.json index 4103826..eb1264d 100644 --- a/unittesting.json +++ b/unittesting.json @@ -1,6 +1,6 @@ { "tests_dir" : "tests", - "pattern" : "*unit_tests.py", + "pattern" : "test_*.py", "async": true, "deferred": false, "verbosity": 1, From d1eb668e3238a13ee7949d102fc9abea214edf45 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 17 Dec 2018 20:24:07 -0200 Subject: [PATCH 099/160] Renamed tests/test_wrap.py key variable to setting_name --- tests/test_wrap.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_wrap.py b/tests/test_wrap.py index 1cda4a2..8b92747 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -56,8 +56,8 @@ def _test_wrap(self, filename, contents, syntax): settings = {} if start.group(1): for setting in start.group(1).split(','): - key, value = setting.split('=') - settings[key] = eval(value) + setting_name, value = setting.split('=') + settings[setting_name] = eval(value) # Open a new view to run the test in. self._wrap_with_scratch(filename, orig, expected, syntax, settings, self._test_wrap_individual) @@ -114,12 +114,12 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): view_settings = view.settings() bad_keys = set(settings.keys()) - set(DEFAULT_SETTINGS.keys()) self.assertEqual(bad_keys, set()) - for key, value in DEFAULT_SETTINGS.items(): - value = settings.get(key, value) + for setting_name, value in DEFAULT_SETTINGS.items(): + value = settings.get(setting_name, value) if value == UNSET: - view_settings.erase(key) + view_settings.erase(setting_name) else: - view_settings.set(key, value) + view_settings.set(setting_name, value) view.run_command('append', {'characters': contents}) f(view) actual = view.substr(sublime.Region(0, view.size())) From afcf9629503f7d12c2eb199793ae3af43d4fd973 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Mon, 17 Dec 2018 20:25:13 -0200 Subject: [PATCH 100/160] Added missing new settings to tests/test_wrap.py default settings --- tests/test_wrap.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_wrap.py b/tests/test_wrap.py index 8b92747..30251a4 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -16,6 +16,8 @@ 'translate_tabs_to_spaces': False, 'WrapPlus.break_long_words': False, 'WrapPlus.break_on_hyphens': False, + 'WrapPlus.after_wrap': 'cursor_below', + 'WrapPlus.semantic_line_wrap': False, 'WrapPlus.include_line_endings': 'auto', 'WrapPlus.wrap_width': UNSET, 'WrapPlus.skip_range': False, # Workaround for a bug. From a1efc7b9183e9a460c96344fc95172e16155a3ce Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 18 Dec 2018 15:52:32 -0200 Subject: [PATCH 101/160] Fixed support for python multiline strings """ lines starts, commimt ffa9164ae289562867147941addc58be6e8d0d8b --- wrap_plus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index 5235cf9..24c7174 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -253,7 +253,7 @@ def CONCAT(*args): return '(?:' + ''.join(args) + ')' -blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*(?:````?.*)?)$|(?:.*"""\\?)') +blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*(?:````?.*)?)$|(?:.*"""\\?$)') next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) whitespace_character = (" ", "\t") From 49c4abd22bbf41da9d313b7a81497ed8be675c07 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 18 Dec 2018 16:17:11 -0200 Subject: [PATCH 102/160] Fixed duplicated line and added missing yes debug messages --- wrap_plus.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 24c7174..4c3e104 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -377,23 +377,25 @@ def _find_paragraph_start(self, point): debug('is_paragraph_break?') if self._is_paragraph_break(current_line_region, current_line): + debug('yes') return current_line_region, current_line debug('no') while 1: # Check if this line is the start of a paragraph. - debug('start?') + debug('is the start of a paragraph?') if self._is_paragraph_start(current_line_region, current_line): - debug('current_line is paragraph start: %r', current_line,) + debug('yes, current_line is paragraph start: %r', current_line,) break + debug('no') # Check if the previous line is a "break" separator. - debug('break?') + debug('previous line is line break?') prev_line_region, prev_line = view.prev_line(current_line_region) if prev_line_region is None: - # current_line is as far up as we're allowed to go. + debug("yes, current_line is as far up as we're allowed to go.") break if self._is_paragraph_break(prev_line_region, prev_line): - debug('prev line %r is a paragraph break', prev_line,) + debug('yes, prev line %r is a paragraph break', prev_line,) break # If the previous line has a comment, and we started in a # non-comment scope, stop. No need to check for comment to @@ -402,9 +404,9 @@ def _find_paragraph_start(self, point): if (not started_in_comment and self.view.score_selector(prev_line_region.end(), 'comment') ): - debug('prev line contains a comment, cannot continue.') + debug('yes, prev line %r contains a comment, cannot continue.', prev_line) break - debug('prev_line %r is part of the paragraph', prev_line,) + debug('no, prev_line %r is part of the paragraph', prev_line,) # Previous line is a part of this paragraph. Add it, and loop # around again. current_line_region = prev_line_region @@ -672,7 +674,6 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): self._width_in_spaces(initial_indent) + 1 ): subsequent_indent = spaces - subsequent_indent = spaces if not subsequent_indent: # Not already indented, make an indent. subsequent_indent = initial_indent + self._make_indent() From 3a23a1d3752931e6e0693d61d67e021e5b670f5e Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 18 Dec 2018 16:21:19 -0200 Subject: [PATCH 103/160] Fixed debug statement not properly formating the string --- wrap_plus.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 4c3e104..4225076 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -113,7 +113,7 @@ def set_comments(self, line_comments, block_comment, point): # Determine if point is inside a "line comment". # Only whitespace is allowed to the left of the line comment. is_generic_config = "source.genconfig" in scope_name - debug( "line_comments: " + str( line_comments ) ) + debug( "line_comments: %s", line_comments ) # When using the generic syntax, the Sublime Text plugin `Default.comment` will return # the default syntax comment prefix `#` instead of the actual line prefix @@ -553,14 +553,14 @@ def _determine_width(self, width): :returns: The maximum line width. """ - # print( "_determine_width, width: " + str( width ) ) + # print( "_determine_width, width: %s" % width ) if width == 0 and self.view.settings().get('wrap_width'): try: width = int(self.view.settings().get('wrap_width')) except TypeError: pass - # print( "_determine_width, before get('rulers'), width: " + str( width ) ) + # print( "_determine_width, before get('rulers'), width: %s" % width ) if width == 0 and self.view.settings().get('rulers'): # try and guess the wrap width from the ruler, if any try: @@ -570,7 +570,7 @@ def _determine_width(self, width): except TypeError: pass - # print( "_determine_width, before get('WrapPlus.wrap_width', width): " + str( width ) ) + # print( "_determine_width, before get('WrapPlus.wrap_width', width): %s" % width ) if width == 0: width = self.view.settings().get('WrapPlus.wrap_width', width) @@ -775,7 +775,7 @@ def run(self, edit, width=0, line_wrap_type=None): # minimum_line_size_percent = 0.0 disable_line_wrapping_by_maximum_width = True - # print( "minimum_line_size_percent: " + str( minimum_line_size_percent ) ) + # print( "minimum_line_size_percent: %s" % minimum_line_size_percent ) if self.get_semantic_line_wrap_setting( view_settings, line_wrap_type ): self._width *= wrap_extension_percent @@ -799,7 +799,7 @@ def line_wrapper_type(): wrapper.width = self._width wrapper.expand_tabs = False - # print( "self._width: " + str( self._width ) ) + # print( "self._width: %s" % self._width ) if paragraphs: # Use view selections to handle shifts from the replace() command. self.view.sel().clear() @@ -908,7 +908,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind new_text.append( subsequent_indent ) new_text.extend( new_lines ) - # print( "balance_characters_between_line_wraps, new_text: " + str( new_text ) ) + # print( "balance_characters_between_line_wraps, new_text: %s" + new_text ) return new_text def is_line_bellow_half_wrap_limit(self, new_lines, subsequent_indent_length): @@ -972,7 +972,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li new_lines.append( fixed_wrapped_lines ) - # print( "_split_lines, new_lines: " + str( new_lines ) ) + # print( "_split_lines, new_lines: %s" % new_lines ) return new_lines def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum_line_width): @@ -992,13 +992,13 @@ def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum while last_line_length != new_line_length \ and lines_count < line_length: - # print( "calculate_lines_count, new_line_length: " + str( new_line_length ) ) + # print( "calculate_lines_count, new_line_length: %s" % new_line_length ) last_line_length = new_line_length lines_count = math.ceil( last_line_length / maximum_line_width ) new_line_length = ( lines_count - 1 ) * subsequent_indent_length + line_length - # print( "calculate_lines_count, lines_count: " + str( lines_count ) ) + # print( "calculate_lines_count, lines_count: %s" % lines_count ) return lines_count, new_line_length def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, @@ -1167,7 +1167,7 @@ def force_flush_accumulated_line(): if len( accumulated_line ): new_text.append(accumulated_line) - # print( "semantic_line_wrap, new_text: " + str( new_text ) ) + # print( "semantic_line_wrap, new_text: %s" % new_text ) return new_text def peek_next_word_length(self, index, text): From 39ac1cb4289bfc0e4b8dd1a9372ad2c5a097bb7c Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 18 Dec 2018 21:26:32 -0200 Subject: [PATCH 104/160] Replaced the builtin debug logger by debug_tools dependency --- Preferences.sublime-settings | 3 + dependencies.json | 7 ++ wrap_plus.py | 149 +++++++++++++++++------------------ 3 files changed, 82 insertions(+), 77 deletions(-) create mode 100644 dependencies.json diff --git a/Preferences.sublime-settings b/Preferences.sublime-settings index 9c9729a..ca859f7 100644 --- a/Preferences.sublime-settings +++ b/Preferences.sublime-settings @@ -89,4 +89,7 @@ // * If the setting `WrapPlus.balance_characters_between_line_wraps` is enabled, // this setting will be ignored. "WrapPlus.semantic_disable_line_wrapping_by_maximum_width": false, + + // Control console debugging messages, it can be false, or bitwise int number + "WrapPlus.debug": false, } diff --git a/dependencies.json b/dependencies.json new file mode 100644 index 0000000..cd19842 --- /dev/null +++ b/dependencies.json @@ -0,0 +1,7 @@ +{ + "*": { + "*": [ + "debugtools" + ] + } +} diff --git a/wrap_plus.py b/wrap_plus.py index 4225076..8585cbb 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1,18 +1,20 @@ from __future__ import print_function import sublime import sublime_plugin -from . import py_textwrap as textwrap -import re -import os +import re import math import time -import unittest + try: import Default.comment as comment except ImportError: import comment +from debug_tools import getLogger + +from . import py_textwrap as textwrap + def is_quoted_string(scope_region, scope_name): # string.quoted.double.block.python @@ -23,32 +25,24 @@ def is_quoted_string(scope_region, scope_name): return 'quoted' in scope_name or 'comment.block.documentation' in scope_name -debug_enabled = False -# debug_enabled = True - time_start = 0 -last_time = 0 - +debug_enabled = 127 +log = getLogger(debug_enabled, "wrap_plus") def debug_start(enabled): - global time_start, last_time - if debug_enabled or enabled: - time_start = time.time() - last_time = time_start + global debug_enabled + if enabled: + debug_enabled = int(enabled) + 1 + log.debug_level = debug_enabled -def debug(msg, *args): - if debug_enabled: - global last_time - t = time.time() - d = t - time_start - print('%.3f (+%.3f) ' % (d, t - last_time), end='') - last_time = t - print(msg % args) + if debug_enabled > 1: + global time_start + time_start = time.time() def debug_end(): - if debug_enabled: + if debug_enabled > 1: print('Total time: %.3f' % (time.time() - time_start)) @@ -107,13 +101,13 @@ def set_comments(self, line_comments, block_comment, point): if not line_stripped: # Empty line, nothing to do. - debug('Empty line, no comment characters found.') + log(2, 'Empty line, no comment characters found.') return # Determine if point is inside a "line comment". # Only whitespace is allowed to the left of the line comment. is_generic_config = "source.genconfig" in scope_name - debug( "line_comments: %s", line_comments ) + log(2, "line_comments: %s", line_comments ) # When using the generic syntax, the Sublime Text plugin `Default.comment` will return # the default syntax comment prefix `#` instead of the actual line prefix @@ -130,7 +124,7 @@ def set_comments(self, line_comments, block_comment, point): for line_comment, is_block_comment in extended_prefixes: line_comment = line_comment.rstrip() - debug( ( "line_comment: %s, line_stripped: %s" % ( line_comment, line_stripped ) ).replace("%", "%%") ) + log(2, ( "line_comment: %s, line_stripped: %s" % ( line_comment, line_stripped ) ).replace("%", "%%") ) if line_stripped.startswith(line_comment): @@ -148,9 +142,9 @@ def set_comments(self, line_comments, block_comment, point): if regex_match: self.required_comment_prefix = regex_match.group() self.required_comment_pattern = email_quote_pattern - debug('doing email style quoting') + log(2, 'doing email style quoting') - debug('scope=%r range=%r', scope_name, scope_region) + log(2, 'scope=%r range=%r', scope_name, scope_region) if self._is_c_comment(scope_name): # Check for C-style commenting with each line starting with an asterisk. @@ -175,9 +169,9 @@ def set_comments(self, line_comments, block_comment, point): end = scope_region.end() - len(regex_match.group(2)) self.min = max(self.min, begin) self.max = min(self.max, end) - debug('Scope narrowed to %i:%i', self.min, self.max) + log(2, 'Scope narrowed to %i:%i', self.min, self.max) - debug('required_comment_prefix determined to be %r', self.required_comment_prefix,) + log(2, 'required_comment_prefix determined to be %r', self.required_comment_prefix,) # Narrow the min/max range if inside a "quoted" string. if is_quoted_string(scope_region, scope_name): @@ -193,15 +187,15 @@ def line(self, where): """ line_region = self.view.line(where) if line_region.begin() < self.min: - debug('line min increased') + log(2, 'line min increased') line_region = sublime.Region(self.min, line_region.end()) if line_region.end() > self.max: - debug('line max lowered') + log(2, 'line max lowered') line_region = sublime.Region(line_region.begin(), self.max) line = self.view.substr(line_region) - debug('line=%r', line) + log(2, 'line=%r', line) if self.required_comment_prefix: - debug('checking required comment prefix %r', self.required_comment_prefix) + log(2, 'checking required comment prefix %r', self.required_comment_prefix) if line.startswith(self.required_comment_prefix): # Check for an insufficient prefix. @@ -230,10 +224,10 @@ def substr(self, r): def next_line(self, where): l_r = self.view.line(where) - debug('next line region=%r', l_r) + log(2, 'next line region=%r', l_r) point = l_r.end() + 1 if point >= self.max: - debug('past max at %r', self.max) + log(2, 'past max at %r', self.max) return None, None return self.line(point) @@ -342,7 +336,7 @@ def _is_paragraph_start(self, line_region, line): return True if numbered_list_pattern.match(line): result = self._is_real_numbered_list(line_region, line) - debug('is {}a paragraph continuation'.format('not ' if result else '')) + log(2, 'is {}a paragraph continuation'.format('not ' if result else '')) return result return False @@ -353,7 +347,7 @@ def _is_paragraph_break(self, line_region, line, pure=False): """ if self._is_blank_line(line): return True scope_name = self.view.scope_name(line_region.begin()) - debug('scope_name=%r (%r)', scope_name, line_region) + log(2, 'scope_name=%r (%r)', scope_name, line_region) if 'heading' in scope_name: return True if pure: @@ -375,27 +369,27 @@ def _find_paragraph_start(self, point): return None, None started_in_comment = self._started_in_comment(point) - debug('is_paragraph_break?') + log(2, 'is_paragraph_break?') if self._is_paragraph_break(current_line_region, current_line): - debug('yes') + log(2, 'yes') return current_line_region, current_line - debug('no') + log(2, 'no') while 1: # Check if this line is the start of a paragraph. - debug('is the start of a paragraph?') + log(2, 'is the start of a paragraph?') if self._is_paragraph_start(current_line_region, current_line): - debug('yes, current_line is paragraph start: %r', current_line,) + log(2, 'yes, current_line is paragraph start: %r', current_line,) break - debug('no') + log(2, 'no') # Check if the previous line is a "break" separator. - debug('previous line is line break?') + log(2, 'previous line is line break?') prev_line_region, prev_line = view.prev_line(current_line_region) if prev_line_region is None: - debug("yes, current_line is as far up as we're allowed to go.") + log(2, "yes, current_line is as far up as we're allowed to go.") break if self._is_paragraph_break(prev_line_region, prev_line): - debug('yes, prev line %r is a paragraph break', prev_line,) + log(2, 'yes, prev line %r is a paragraph break', prev_line,) break # If the previous line has a comment, and we started in a # non-comment scope, stop. No need to check for comment to @@ -404,9 +398,9 @@ def _find_paragraph_start(self, point): if (not started_in_comment and self.view.score_selector(prev_line_region.end(), 'comment') ): - debug('yes, prev line %r contains a comment, cannot continue.', prev_line) + log(2, 'yes, prev line %r contains a comment, cannot continue.', prev_line) break - debug('no, prev_line %r is part of the paragraph', prev_line,) + log(2, 'no, prev_line %r is part of the paragraph', prev_line,) # Previous line is a part of this paragraph. Add it, and loop # around again. current_line_region = prev_line_region @@ -424,7 +418,7 @@ def _find_paragraphs(self, sublime_text_region): :returns: A list of (region, lines, comment_prefix) of each paragraph. """ result = [] - debug('find paragraphs sublime_text_region=%r', sublime_text_region,) + log(2, 'find paragraphs sublime_text_region=%r', sublime_text_region,) if sublime_text_region.empty(): is_empty = True view_min = 0 @@ -440,32 +434,32 @@ def _find_paragraphs(self, sublime_text_region): # Loop for each paragraph (only loops once if sublime_text_region is empty). paragraph_start_pt = sublime_text_region.begin() while 1: - debug('paragraph scanning start %r.', paragraph_start_pt,) + log(2, 'paragraph scanning start %r.', paragraph_start_pt,) view.set_comments(self._line_comment, self._is_block_comment, paragraph_start_pt) lines = [] if is_empty: # Find the beginning of this paragraph. - debug('empty sel finding paragraph start.') + log(2, 'empty sel finding paragraph start.') current_line_region, current_line = self._find_paragraph_start(paragraph_start_pt) - debug('empty sel paragraph start determined to be %r %r', + log(2, 'empty sel paragraph start determined to be %r %r', current_line_region, current_line) else: # The selection defines the beginning. current_line_region, current_line = view.line(paragraph_start_pt) - debug('sel beggining = %r %r', current_line_region, current_line) + log(2, 'sel beggining = %r %r', current_line_region, current_line) if current_line_region is None: - debug('Could not find start.') + log(2, 'Could not find start.') return [] # Skip blank and unambiguous break lines. while 1: - debug('skip blank line') + log(2, 'skip blank line') if not self._is_paragraph_break(current_line_region, current_line, pure=True): - debug('not paragraph break') + log(2, 'not paragraph break') break if is_empty: - debug('empty sel on paragraph break %r', current_line,) + log(2, 'empty sel on paragraph break %r', current_line,) return [] current_line_region, current_line = view.next_line(current_line_region) @@ -473,16 +467,16 @@ def _find_paragraphs(self, sublime_text_region): paragraph_end_pt = current_line_region.end() # current_line_region now points to the beginning of the paragraph. # Move down until the end of the paragraph. - debug('Scan until end of paragraph.') + log(2, 'Scan until end of paragraph.') while 1: - debug('current_line_region=%r max=%r', current_line_region, view.max) + log(2, 'current_line_region=%r max=%r', current_line_region, view.max) # If we started in a non-comment scope, and the end of the # line contains a comment, include any non-comment text in the # wrap and stop looking for more. if (not started_in_comment and self.view.score_selector(current_line_region.end(), 'comment') ): - debug('end of paragraph hit a comment.') + log(2, 'end of paragraph hit a comment.') # Find the start of the comment. # This assumes comments do not have multiple scopes. comment_r = self.view.extract_scope(current_line_region.end()) @@ -495,7 +489,7 @@ def _find_paragraphs(self, sublime_text_region): regex_match = re.search('([ \t]+$)', region_substring) if regex_match: end_pt -= len(regex_match.group(1)) - debug('non-comment contents are: %r', region_substring) + log(2, 'non-comment contents are: %r', region_substring) paragraph_end_pt = end_pt lines.append(region_substring) # Skip over the comment. @@ -508,14 +502,14 @@ def _find_paragraphs(self, sublime_text_region): current_line_region, current_line = view.next_line(current_line_region) if current_line_region is None: # Line is outside of our range. - debug('Out of range, stopping.') + log(2, 'Out of range, stopping.') break - debug('current_line = %r %r', current_line_region, current_line) + log(2, 'current_line = %r %r', current_line_region, current_line) if self._is_paragraph_break(current_line_region, current_line): - debug('current line is a break, stopping.') + log(2, 'current line is a break, stopping.') break if self._is_paragraph_start(current_line_region, current_line): - debug('current line is a paragraph start, stopping.') + log(2, 'current line is a paragraph start, stopping.') break paragraph_region = sublime.Region(paragraph_start_pt, paragraph_end_pt) @@ -526,7 +520,7 @@ def _find_paragraphs(self, sublime_text_region): # Skip over blank lines and break lines till the next paragraph # (or end of range). - debug('skip over blank lines') + log(2, 'skip over blank lines') while current_line_region is not None: if self._is_paragraph_start(current_line_region, current_line): break @@ -538,7 +532,7 @@ def _find_paragraphs(self, sublime_text_region): if current_line_region is None: break - debug('next_paragraph_start is %r %r', current_line_region, current_line) + log(2, 'next_paragraph_start is %r %r', current_line_region, current_line) paragraph_start_pt = current_line_region.begin() if paragraph_start_pt >= view_max: break @@ -705,7 +699,7 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): true_first_line = self.view.substr(true_first_line_r) if true_first_line_r.begin() <= scope_region.begin(): regex_match = space_prefix_pattern.match(true_first_line) - debug('single line quoted string triggered') + log(2, 'single line quoted string triggered') if regex_match: subsequent_indent = regex_match.group() + subsequent_indent @@ -717,7 +711,7 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): line = line[len(subsequent_indent):] new_lines.append(line.strip()) - debug('initial_indent=%r subsequent_indent=%r', initial_indent, subsequent_indent) + log(2, 'initial_indent=%r subsequent_indent=%r', initial_indent, subsequent_indent) return (required_comment_prefix + initial_indent, required_comment_prefix + subsequent_indent, @@ -737,8 +731,9 @@ def get_semantic_line_wrap_setting(self, view_settings, line_wrap_type): return is_semantic_line_wrap def run(self, edit, width=0, line_wrap_type=None): - debug_start(self.view.settings().get('WrapPlus.debug', False)) - debug('\n\n#########################################################################') + debug_enabled = self.view.settings().get('WrapPlus.debug', False) + debug_start(debug_enabled) + log(2, '\n\n#########################################################################') cursor_original_positions = [] self._width = self._determine_width(width) @@ -751,13 +746,13 @@ def run(self, edit, width=0, line_wrap_type=None): paragraphs = [] for selection in self.view.sel(): - debug('examine %r', selection) + log(2, 'examine %r', selection) paragraphs.extend(self._find_paragraphs(selection)) cursor_original_positions.append(selection.begin()) view_settings = self.view.settings() - debug('paragraphs is %r', paragraphs) + log(2, 'paragraphs is %r', paragraphs) after_wrap = view_settings.get('WrapPlus.after_wrap', "cursor_below") break_long_words = view_settings.get('WrapPlus.break_long_words', False) @@ -1265,9 +1260,9 @@ def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent lines = text.splitlines() if initial_indent != orig_initial_indent: - debug('fix tabs %r', lines[0]) + log(2, 'fix tabs %r', lines[0]) lines[0] = orig_initial_indent + lines[0][len(initial_indent):] - debug('new line is %r', lines[0]) + log(2, 'new line is %r', lines[0]) if subsequent_indent != orig_subsequent_indent: @@ -1300,9 +1295,9 @@ def print_text_replacements(self, text, selection): replaced_txt = self.view.substr(selection) if replaced_txt != text: - debug('replaced text not the same:\noriginal=%r\nnew=%r', replaced_txt, text) + log(2, 'replaced text not the same:\noriginal=%r\nnew=%r', replaced_txt, text) else: - debug('replaced text is the same') + log(2, 'replaced text is the same') last_used_width = 80 From 8ad496a4567b4503ecd580b1309c6ad68da0a542 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 18 Dec 2018 21:28:07 -0200 Subject: [PATCH 105/160] Enabled all commented out print statements as log debug level 4 --- wrap_plus.py | 58 ++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 8585cbb..5e3157b 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -266,7 +266,7 @@ def CONCAT(*args): field_start = r'(?:[:@])' # rest, javadoc, jsdoc, etc. new_paragraph_pattern_string = r'^[\t ]*' + OR(lettered_list, bullet_list, field_start, r'\{') -# print( "pattern: " + new_paragraph_pattern_string ) +log(4, "pattern: " + new_paragraph_pattern_string ) new_paragraph_pattern = re.compile(new_paragraph_pattern_string) space_prefix_pattern = re.compile(r'^[ \t]*') @@ -547,14 +547,14 @@ def _determine_width(self, width): :returns: The maximum line width. """ - # print( "_determine_width, width: %s" % width ) + log(4, "_determine_width, width: %s" % width ) if width == 0 and self.view.settings().get('wrap_width'): try: width = int(self.view.settings().get('wrap_width')) except TypeError: pass - # print( "_determine_width, before get('rulers'), width: %s" % width ) + log(4, "_determine_width, before get('rulers'), width: %s" % width ) if width == 0 and self.view.settings().get('rulers'): # try and guess the wrap width from the ruler, if any try: @@ -564,7 +564,7 @@ def _determine_width(self, width): except TypeError: pass - # print( "_determine_width, before get('WrapPlus.wrap_width', width): %s" % width ) + log(4, "_determine_width, before get('WrapPlus.wrap_width', width): %s" % width ) if width == 0: width = self.view.settings().get('WrapPlus.wrap_width', width) @@ -738,7 +738,7 @@ def run(self, edit, width=0, line_wrap_type=None): cursor_original_positions = [] self._width = self._determine_width(width) - # print('wrap width = %r', self._width) + log(4,'wrap width = %r', self._width) self._determine_tab_size() self._determine_comment_style() @@ -770,7 +770,7 @@ def run(self, edit, width=0, line_wrap_type=None): # minimum_line_size_percent = 0.0 disable_line_wrapping_by_maximum_width = True - # print( "minimum_line_size_percent: %s" % minimum_line_size_percent ) + log(4, "minimum_line_size_percent: %s" % minimum_line_size_percent ) if self.get_semantic_line_wrap_setting( view_settings, line_wrap_type ): self._width *= wrap_extension_percent @@ -782,7 +782,7 @@ def line_wrapper_type(): if balance_characters_between_line_wraps: text = self.balance_characters_between_line_wraps( wrapper, text, initial_indent, subsequent_indent ) - # print( 'run, text: ' + "".join( text ) ) + log(4, 'run, text: ' + "".join( text ) ) return "".join( text ) else: @@ -794,7 +794,7 @@ def line_wrapper_type(): wrapper.width = self._width wrapper.expand_tabs = False - # print( "self._width: %s" % self._width ) + log(4, "self._width: %s" % self._width ) if paragraphs: # Use view selections to handle shifts from the replace() command. self.view.sel().clear() @@ -873,7 +873,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind break - # print( "\nShrinking the lines..." ) + log(4, "\nShrinking the lines..." ) new_lines_backup = list( new_lines ) if self.is_there_line_over_the_wrap_limit( new_lines ): @@ -903,7 +903,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind new_text.append( subsequent_indent ) new_text.extend( new_lines ) - # print( "balance_characters_between_line_wraps, new_text: %s" + new_text ) + log(4, "balance_characters_between_line_wraps, new_text: %s" + new_text ) return new_text def is_line_bellow_half_wrap_limit(self, new_lines, subsequent_indent_length): @@ -938,7 +938,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li for step in range( 1, lines_count + 1 ): new_line_length = math.ceil( line_length / step ) - # print( "_split_lines, new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) + log(4, "_split_lines, new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) if new_line_length > maximum_line_width: continue @@ -946,13 +946,13 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li else: break - # print( "_split_lines, maximum_line_width: %d, new_width: %d (%f)" % ( maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) + log(4, "_split_lines, maximum_line_width: %d, new_width: %d (%f)" % ( maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) wrapper.width = math.ceil( new_line_length * middle_of_the_line_increment_percent ) - # print( "_split_lines, line: " + line ) + log(4, "_split_lines, line: " + line ) wrapped_line = wrapper.fill( line ) - # print( "_split_lines, wrapped_line: " + wrapped_line ) + log(4, "_split_lines, wrapped_line: " + wrapped_line ) wrapped_lines = wrapped_line.split( "\n" ) # Add again the removed `\n` character due the `split` statement @@ -967,7 +967,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li new_lines.append( fixed_wrapped_lines ) - # print( "_split_lines, new_lines: %s" % new_lines ) + log(4, "_split_lines, new_lines: %s" % new_lines ) return new_lines def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum_line_width): @@ -987,13 +987,13 @@ def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum while last_line_length != new_line_length \ and lines_count < line_length: - # print( "calculate_lines_count, new_line_length: %s" % new_line_length ) + log(4, "calculate_lines_count, new_line_length: %s" % new_line_length ) last_line_length = new_line_length lines_count = math.ceil( last_line_length / maximum_line_width ) new_line_length = ( lines_count - 1 ) * subsequent_indent_length + line_length - # print( "calculate_lines_count, lines_count: %s" % lines_count ) + log(4, "calculate_lines_count, lines_count: %s" % lines_count ) return lines_count, new_line_length def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, @@ -1024,7 +1024,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, text_length = len(text) minimum_line_size = int( self._width * minimum_line_size_percent ) - # print( "minimum_line_size: %s" % ( minimum_line_size ) ) + log(4, "minimum_line_size: %s" % ( minimum_line_size ) ) indent_length = initial_indent_length accumulated_line = "" @@ -1036,7 +1036,7 @@ def force_flush_accumulated_line(): nonlocal index nonlocal is_flushing_accumalated_line - # print( "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) + log(4, "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) is_flushing_accumalated_line = True # Current character is a whitespace, but it must the the next, so fix the index @@ -1059,7 +1059,7 @@ def force_flush_accumulated_line(): comma_list_size -= 1 last_comma_list_size = comma_list_size + 1 - # print( "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, comma_list_end_point, character ) ) + log(4, "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, comma_list_end_point, character ) ) if not is_flushing_accumalated_line: if not disable_line_wrapping_by_maximum_width \ @@ -1086,7 +1086,7 @@ def force_flush_accumulated_line(): is_flushing_comma_list = False is_comma_separated_list = False - # print( "semantic_line_wrap, index: %d, character: %s " % ( index, character ) ) + log(4, "semantic_line_wrap, index: %d, character: %s " % ( index, character ) ) if not disable_line_wrapping_by_maximum_width \ and not is_flushing_accumalated_line \ and accumulated_line_length + next_word_length + indent_length > self._width: @@ -1119,7 +1119,7 @@ def force_flush_accumulated_line(): comma_list_size = -1 is_comma_separated_list = False - # print( "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)" % ( index, comma_list_size, self.maximum_items_in_comma_separated_list ) ) + log(4, "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)" % ( index, comma_list_size, self.maximum_items_in_comma_separated_list ) ) if ( is_comma_separated_list \ and comma_list_size > -1 ) \ and not is_flushing_comma_list \ @@ -1136,7 +1136,7 @@ def force_flush_accumulated_line(): accumulated_line = "".join( [accumulated_line, character, "\n", ( "" if balance_characters_between_line_wraps else subsequent_indent ) ] ) - # print( "semantic_line_wrap, accumulated_line flush: %r" % accumulated_line ) + log(4, "semantic_line_wrap, accumulated_line flush: %r" % accumulated_line ) new_text.append( accumulated_line ) accumulated_line = "" @@ -1162,7 +1162,7 @@ def force_flush_accumulated_line(): if len( accumulated_line ): new_text.append(accumulated_line) - # print( "semantic_line_wrap, new_text: %s" % new_text ) + log(4, "semantic_line_wrap, new_text: %s" % new_text ) return new_text def peek_next_word_length(self, index, text): @@ -1171,7 +1171,7 @@ def peek_next_word_length(self, index, text): if match: next_word = match.group(0) - # print( "peek_next_word_length: %s" % next_word ) + log(4, "peek_next_word_length: %s" % next_word ) return len( next_word ) return 0 @@ -1181,7 +1181,7 @@ def is_comma_separated_list(self, text, index): return if the next characters form a command separated list return 0 if False, otherwise the `text` index where the command separated list ended """ - # print( "is_comma_separated_list, index: %d" % ( index ) ) + log(4, "is_comma_separated_list, index: %d" % ( index ) ) comma_list_end_point = -1 # A word list has at least 2 items. For example: start 1, 2, 3 words @@ -1210,7 +1210,7 @@ def is_comma_separated_list(self, text, index): if is_character_whitespace and not is_next_character_whitepace: words_counter += 1 - # print( "is_comma_separated_list, index: %d, words_counter: %d, character: %s, next_character: %s" % ( index, words_counter, character, next_character ) ) + log(4, "is_comma_separated_list, index: %d, words_counter: %d, character: %s, next_character: %s" % ( index, words_counter, character, next_character ) ) if is_word_separator_character and is_next_character_whitepace: if 0 < words_counter < self.maximum_words_in_comma_separated_list: @@ -1227,10 +1227,10 @@ def is_comma_separated_list(self, text, index): words_counter = 0 if comma_list_end_point > -1: - # print( "is_comma_separated_list (True), comma_list_end_point: %d, comma_separated_list_items_count: %d" % ( comma_list_end_point, comma_separated_list_items_count ) ) + log(4, "is_comma_separated_list (True), comma_list_end_point: %d, comma_separated_list_items_count: %d" % ( comma_list_end_point, comma_separated_list_items_count ) ) return True, comma_list_end_point, comma_separated_list_items_count - # print( "is_comma_separated_list (False), comma_list_end_point: %d, comma_separated_list_items_count: %d" % ( 0, 0 ) ) + log(4, "is_comma_separated_list (False), comma_list_end_point: %d, comma_separated_list_items_count: %d" % ( 0, 0 ) ) return False, 0, 0 def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent_indent): From a16f6df1984e5f190ab34dca0f606467cec07756 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 18 Dec 2018 21:49:03 -0200 Subject: [PATCH 106/160] Fixed log comments directly formatting the input string with % (,) --- wrap_plus.py | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 5e3157b..bea5cef 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -43,7 +43,7 @@ def debug_start(enabled): def debug_end(): if debug_enabled > 1: - print('Total time: %.3f' % (time.time() - time_start)) + log(1, 'Total time: %.3f', time.time() - time_start) class PrefixStrippingView(object): @@ -124,7 +124,7 @@ def set_comments(self, line_comments, block_comment, point): for line_comment, is_block_comment in extended_prefixes: line_comment = line_comment.rstrip() - log(2, ( "line_comment: %s, line_stripped: %s" % ( line_comment, line_stripped ) ).replace("%", "%%") ) + log(2, "line_comment: %s, line_stripped: %s", line_comment, line_stripped ) if line_stripped.startswith(line_comment): @@ -547,14 +547,14 @@ def _determine_width(self, width): :returns: The maximum line width. """ - log(4, "_determine_width, width: %s" % width ) + log(4, "_determine_width, width: %s", width ) if width == 0 and self.view.settings().get('wrap_width'): try: width = int(self.view.settings().get('wrap_width')) except TypeError: pass - log(4, "_determine_width, before get('rulers'), width: %s" % width ) + log(4, "_determine_width, before get('rulers'), width: %s", width ) if width == 0 and self.view.settings().get('rulers'): # try and guess the wrap width from the ruler, if any try: @@ -564,7 +564,7 @@ def _determine_width(self, width): except TypeError: pass - log(4, "_determine_width, before get('WrapPlus.wrap_width', width): %s" % width ) + log(4, "_determine_width, before get('WrapPlus.wrap_width', width): %s", width ) if width == 0: width = self.view.settings().get('WrapPlus.wrap_width', width) @@ -770,7 +770,7 @@ def run(self, edit, width=0, line_wrap_type=None): # minimum_line_size_percent = 0.0 disable_line_wrapping_by_maximum_width = True - log(4, "minimum_line_size_percent: %s" % minimum_line_size_percent ) + log(4, "minimum_line_size_percent: %s", minimum_line_size_percent ) if self.get_semantic_line_wrap_setting( view_settings, line_wrap_type ): self._width *= wrap_extension_percent @@ -794,7 +794,7 @@ def line_wrapper_type(): wrapper.width = self._width wrapper.expand_tabs = False - log(4, "self._width: %s" % self._width ) + log(4, "self._width: %s", self._width ) if paragraphs: # Use view selections to handle shifts from the replace() command. self.view.sel().clear() @@ -903,7 +903,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind new_text.append( subsequent_indent ) new_text.extend( new_lines ) - log(4, "balance_characters_between_line_wraps, new_text: %s" + new_text ) + log(4, "balance_characters_between_line_wraps, new_text: %s", new_text ) return new_text def is_line_bellow_half_wrap_limit(self, new_lines, subsequent_indent_length): @@ -938,7 +938,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li for step in range( 1, lines_count + 1 ): new_line_length = math.ceil( line_length / step ) - log(4, "_split_lines, new_line_length: %d, lines_count: %d" % ( new_line_length, lines_count ) ) + log(4, "_split_lines, new_line_length: %d, lines_count: %d", new_line_length, lines_count ) if new_line_length > maximum_line_width: continue @@ -946,7 +946,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li else: break - log(4, "_split_lines, maximum_line_width: %d, new_width: %d (%f)" % ( maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) ) + log(4, "_split_lines, maximum_line_width: %d, new_width: %d (%f)", maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) wrapper.width = math.ceil( new_line_length * middle_of_the_line_increment_percent ) log(4, "_split_lines, line: " + line ) @@ -967,7 +967,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li new_lines.append( fixed_wrapped_lines ) - log(4, "_split_lines, new_lines: %s" % new_lines ) + log(4, "_split_lines, new_lines: %s", new_lines ) return new_lines def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum_line_width): @@ -987,13 +987,13 @@ def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum while last_line_length != new_line_length \ and lines_count < line_length: - log(4, "calculate_lines_count, new_line_length: %s" % new_line_length ) + log(4, "calculate_lines_count, new_line_length: %s", new_line_length ) last_line_length = new_line_length lines_count = math.ceil( last_line_length / maximum_line_width ) new_line_length = ( lines_count - 1 ) * subsequent_indent_length + line_length - log(4, "calculate_lines_count, lines_count: %s" % lines_count ) + log(4, "calculate_lines_count, lines_count: %s", lines_count ) return lines_count, new_line_length def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, @@ -1024,7 +1024,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, text_length = len(text) minimum_line_size = int( self._width * minimum_line_size_percent ) - log(4, "minimum_line_size: %s" % ( minimum_line_size ) ) + log(4, "minimum_line_size: %s", minimum_line_size ) indent_length = initial_indent_length accumulated_line = "" @@ -1036,7 +1036,7 @@ def force_flush_accumulated_line(): nonlocal index nonlocal is_flushing_accumalated_line - log(4, "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d" % ( next_word_length ) ) + log(4, "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d", next_word_length ) is_flushing_accumalated_line = True # Current character is a whitespace, but it must the the next, so fix the index @@ -1059,7 +1059,7 @@ def force_flush_accumulated_line(): comma_list_size -= 1 last_comma_list_size = comma_list_size + 1 - log(4, "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, comma_list_end_point: %d, character: %s" % ( index, accumulated_line_length, comma_list_size, comma_list_end_point, character ) ) + log(4, "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, comma_list_end_point: %d, character: %s", index, accumulated_line_length, comma_list_size, comma_list_end_point, character ) if not is_flushing_accumalated_line: if not disable_line_wrapping_by_maximum_width \ @@ -1086,7 +1086,7 @@ def force_flush_accumulated_line(): is_flushing_comma_list = False is_comma_separated_list = False - log(4, "semantic_line_wrap, index: %d, character: %s " % ( index, character ) ) + log(4, "semantic_line_wrap, index: %d, character: %s ", index, character ) if not disable_line_wrapping_by_maximum_width \ and not is_flushing_accumalated_line \ and accumulated_line_length + next_word_length + indent_length > self._width: @@ -1119,7 +1119,7 @@ def force_flush_accumulated_line(): comma_list_size = -1 is_comma_separated_list = False - log(4, "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)" % ( index, comma_list_size, self.maximum_items_in_comma_separated_list ) ) + log(4, "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)", index, comma_list_size, self.maximum_items_in_comma_separated_list ) if ( is_comma_separated_list \ and comma_list_size > -1 ) \ and not is_flushing_comma_list \ @@ -1136,7 +1136,7 @@ def force_flush_accumulated_line(): accumulated_line = "".join( [accumulated_line, character, "\n", ( "" if balance_characters_between_line_wraps else subsequent_indent ) ] ) - log(4, "semantic_line_wrap, accumulated_line flush: %r" % accumulated_line ) + log(4, "semantic_line_wrap, accumulated_line flush: %r", accumulated_line ) new_text.append( accumulated_line ) accumulated_line = "" @@ -1162,7 +1162,7 @@ def force_flush_accumulated_line(): if len( accumulated_line ): new_text.append(accumulated_line) - log(4, "semantic_line_wrap, new_text: %s" % new_text ) + log(4, "semantic_line_wrap, new_text: %s", new_text ) return new_text def peek_next_word_length(self, index, text): @@ -1171,7 +1171,7 @@ def peek_next_word_length(self, index, text): if match: next_word = match.group(0) - log(4, "peek_next_word_length: %s" % next_word ) + log(4, "peek_next_word_length: %s", next_word ) return len( next_word ) return 0 @@ -1181,7 +1181,7 @@ def is_comma_separated_list(self, text, index): return if the next characters form a command separated list return 0 if False, otherwise the `text` index where the command separated list ended """ - log(4, "is_comma_separated_list, index: %d" % ( index ) ) + log(4, "is_comma_separated_list, index: %d", index ) comma_list_end_point = -1 # A word list has at least 2 items. For example: start 1, 2, 3 words @@ -1210,7 +1210,7 @@ def is_comma_separated_list(self, text, index): if is_character_whitespace and not is_next_character_whitepace: words_counter += 1 - log(4, "is_comma_separated_list, index: %d, words_counter: %d, character: %s, next_character: %s" % ( index, words_counter, character, next_character ) ) + log(4, "is_comma_separated_list, index: %d, words_counter: %d, character: %s, next_character: %s", index, words_counter, character, next_character ) if is_word_separator_character and is_next_character_whitepace: if 0 < words_counter < self.maximum_words_in_comma_separated_list: @@ -1227,10 +1227,10 @@ def is_comma_separated_list(self, text, index): words_counter = 0 if comma_list_end_point > -1: - log(4, "is_comma_separated_list (True), comma_list_end_point: %d, comma_separated_list_items_count: %d" % ( comma_list_end_point, comma_separated_list_items_count ) ) + log(4, "is_comma_separated_list (True), comma_list_end_point: %d, comma_separated_list_items_count: %d", comma_list_end_point, comma_separated_list_items_count ) return True, comma_list_end_point, comma_separated_list_items_count - log(4, "is_comma_separated_list (False), comma_list_end_point: %d, comma_separated_list_items_count: %d" % ( 0, 0 ) ) + log(4, "is_comma_separated_list (False), comma_list_end_point: %d, comma_separated_list_items_count: %d", 0, 0 ) return False, 0, 0 def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent_indent): From 26d8209483891c805c6fa02431283346280b81d5 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 19 Dec 2018 20:28:54 -0200 Subject: [PATCH 107/160] Allowed the debug logger log to a file and clean the log file each time the logger is created. --- wrap_plus.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/wrap_plus.py b/wrap_plus.py index bea5cef..5c2dc49 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -27,8 +27,15 @@ def is_quoted_string(scope_region, scope_name): time_start = 0 debug_enabled = 127 +# log = getLogger(debug_enabled, "wrap_plus", "wrapplus.txt", mode='w') log = getLogger(debug_enabled, "wrap_plus") + +def plugin_unloaded(): + # Unlocks the log file, if any + log.delete() + + def debug_start(enabled): global debug_enabled From da5ebb2c0ce3edcd33ceb04b6de7a89a995d3fc2 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 16:55:55 -0200 Subject: [PATCH 108/160] Revert Fixed redundant text wrapper object creations on wrap_plus.py Commit: 6564b2024f015ff823645960986ba3785454e4c2 Fixing: 7.2. test 7 Test 8: ... Being converted to --> 7.2. test 7 7.2. Test 8: ... --- tests/wrap_tests/test_tab.txt | 19 ------------------- wrap_plus.py | 8 ++++---- 2 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 tests/wrap_tests/test_tab.txt diff --git a/tests/wrap_tests/test_tab.txt b/tests/wrap_tests/test_tab.txt deleted file mode 100644 index 99cb255..0000000 --- a/tests/wrap_tests/test_tab.txt +++ /dev/null @@ -1,19 +0,0 @@ -Packages/Text/Plain text.tmLanguage -===tab_size=4 - 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 - - 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345 ---- - 123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234 - - 123456789 123456789 123456789 123456789 123456789 123456789 123456789 - 12345 -===tab_size=8 - 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 - - 123456789 123456789 123456789 123456789 123456789 123456789 12345678901 ---- - 123456789 123456789 123456789 123456789 123456789 123456789 1234567890 - - 123456789 123456789 123456789 123456789 123456789 123456789 - 12345678901 diff --git a/wrap_plus.py b/wrap_plus.py index 5c2dc49..7e90986 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -797,10 +797,6 @@ def line_wrapper_type(): def line_wrapper_type(): return self.classic_wrap_text(wrapper, paragraph_lines, initial_indent, subsequent_indent) - wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) - wrapper.width = self._width - wrapper.expand_tabs = False - log(4, "self._width: %s", self._width ) if paragraphs: # Use view selections to handle shifts from the replace() command. @@ -813,6 +809,10 @@ def line_wrapper_type(): for index, selection in enumerate(self.view.sel()): paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] + wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) + wrapper.width = self._width + wrapper.expand_tabs = False + initial_indent, subsequent_indent, paragraph_lines = self._extract_prefix( paragraph_region, paragraph_lines, required_comment_prefix) From f38ee4956c76533b10206d9986e14a569db22162 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 18:26:57 -0200 Subject: [PATCH 109/160] Added new logging statements and improved sep_line formatting --- wrap_plus.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 7e90986..3365472 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -27,8 +27,8 @@ def is_quoted_string(scope_region, scope_name): time_start = 0 debug_enabled = 127 -# log = getLogger(debug_enabled, "wrap_plus", "wrapplus.txt", mode='w') -log = getLogger(debug_enabled, "wrap_plus") +log = getLogger(debug_enabled, "wrap_plus", "wrapplus.txt", mode='w') +# log = getLogger(debug_enabled, "wrap_plus") def plugin_unloaded(): @@ -283,9 +283,9 @@ def CONCAT(*args): field_pattern = re.compile(r'^([ \t]*)' + fields) # rest, javadoc, jsdoc, etc sep_chars = '!@#$%^&*=+`~\'\":;.,?_-' -sep_line = '[' + sep_chars + r']+[ \t' + sep_chars + ']*' +sep_line = r'[{sep}]+[(?: |\t){sep}]*'.format(sep=sep_chars) -# Break pattern is a little ambiguous. Something like "# Header" could also be a list element. +# Break pattern is a little ambiguous. Something like "# Header" could also be a list element. break_pattern = re.compile(r'^[\t ]*' + OR(sep_line, OR(latex_hack, rest_directive) + '.*') + '$') pure_break_pattern = re.compile(r'^[\t ]*' + sep_line + '$') @@ -340,30 +340,39 @@ def _is_paragraph_start(self, line_region, line): # Certain patterns at the beginning of the line indicate this is the # beginning of a paragraph. if new_paragraph_pattern.match(line): + log(2, 'is not a new paragraph') return True if numbered_list_pattern.match(line): result = self._is_real_numbered_list(line_region, line) - log(2, 'is {}a paragraph continuation'.format('not ' if result else '')) + log(2, 'is %sa paragraph continuation', 'not ' if result else '') return result + log(2, 'is not a paragraph') return False def _is_paragraph_break(self, line_region, line, pure=False): """A paragraph "break" is something like a blank line, or a horizontal line, - or anything that should not be wrapped and treated like a blank line + or anything that should not be wrapped and treated like a blank line (i.e. ignored). """ if self._is_blank_line(line): return True scope_name = self.view.scope_name(line_region.begin()) - log(2, 'scope_name=%r (%r)', scope_name, line_region) + log(2, 'scope_name=%r %r line=%r', scope_name, line_region, line) if 'heading' in scope_name: + log(2, "'heading' in scope_name") return True if pure: - return pure_break_pattern.match(line) is not None + pure_break = pure_break_pattern.match(line) is not None + log(2, 'pure_break:', pure_break) + return pure_break else: - return break_pattern.match(line) is not None + normal_break = break_pattern.match(line) is not None + log(2, 'normal_break:', normal_break) + return normal_break def _is_blank_line(self, line): - return blank_line_pattern.match(line) is not None + is_blank_line = blank_line_pattern.match(line) is not None + log(2, is_blank_line) + return is_blank_line def _find_paragraph_start(self, point): """Start at point and move up to find where the paragraph starts. @@ -453,7 +462,7 @@ def _find_paragraphs(self, sublime_text_region): else: # The selection defines the beginning. current_line_region, current_line = view.line(paragraph_start_pt) - log(2, 'sel beggining = %r %r', current_line_region, current_line) + log(2, 'sel beginning = %r %r', current_line_region, current_line) if current_line_region is None: log(2, 'Could not find start.') @@ -461,9 +470,9 @@ def _find_paragraphs(self, sublime_text_region): # Skip blank and unambiguous break lines. while 1: - log(2, 'skip blank line') + log(2, 'skip blank line?') if not self._is_paragraph_break(current_line_region, current_line, pure=True): - log(2, 'not paragraph break') + log(2, 'yes, not paragraph break') break if is_empty: log(2, 'empty sel on paragraph break %r', current_line,) @@ -656,6 +665,8 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): regex_match = list_pattern.match(first_line) if regex_match: initial_indent = first_line[0:regex_match.end()] + log(2, 'setting initial_indent:', initial_indent) + stripped_prefix = initial_indent.lstrip() leading_whitespace = initial_indent[:len(initial_indent) - len(stripped_prefix)] subsequent_indent = leading_whitespace + ' ' * self._width_in_spaces(stripped_prefix) @@ -664,6 +675,7 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): if regex_match: # The spaces in front of the field start. initial_indent = regex_match.group(1) + log(2, 'setting initial_indent:', initial_indent) if len(lines) > 1: # How to handle subsequent lines. regex_match = space_prefix_pattern.match(lines[1]) From a5dab0369a32eef70cd47c0ab9325ecdf4badf57 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 20:16:24 -0200 Subject: [PATCH 110/160] Set the unittesting.json "verbosity": 2 --- unittesting.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittesting.json b/unittesting.json index eb1264d..77c2ae5 100644 --- a/unittesting.json +++ b/unittesting.json @@ -3,7 +3,7 @@ "pattern" : "test_*.py", "async": true, "deferred": false, - "verbosity": 1, + "verbosity": 2, "capture_console": true, "output": null } From 35dcb4cb2e8a9d309f3e614875aab8d6338159bd Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 20:22:29 -0200 Subject: [PATCH 111/160] Fixed text_extraction.py name to test_extraction.py --- tests/{text_extraction.py => test_extraction.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{text_extraction.py => test_extraction.py} (100%) diff --git a/tests/text_extraction.py b/tests/test_extraction.py similarity index 100% rename from tests/text_extraction.py rename to tests/test_extraction.py From de396b78d3a9f10283c8deb616c516267293fd93 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 20:24:49 -0200 Subject: [PATCH 112/160] Temporarily disabled .travis.yml and appveyor.yml python-codacy-coverage commands, until ehuss/Sublime-Wrap-Plus#66 gets merged. --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8b832bd..1550266 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,7 +61,7 @@ script: coveralls; codecov; coverage xml -o coverage.xml; - python-codacy-coverage; + # python-codacy-coverage; fi diff --git a/appveyor.yml b/appveyor.yml index 3e75086..03278f7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,4 +30,4 @@ on_finish: - python --version - echo %PATH% - coverage xml -o coverage.xml - - python-codacy-coverage + # - python-codacy-coverage From 2d4d9b699ec2016005fa812021369ce9ec020574 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 20:27:28 -0200 Subject: [PATCH 113/160] Set the wrap_plus.py debug level to 1 and disabled the file logger --- wrap_plus.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 3365472..6f08a0b 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -26,9 +26,9 @@ def is_quoted_string(scope_region, scope_name): time_start = 0 -debug_enabled = 127 -log = getLogger(debug_enabled, "wrap_plus", "wrapplus.txt", mode='w') -# log = getLogger(debug_enabled, "wrap_plus") +debug_enabled = 1 +# log = getLogger(debug_enabled, "wrap_plus", "wrapplus.txt", mode='w') +log = getLogger(debug_enabled, "wrap_plus") def plugin_unloaded(): From c698a50bda46369726e8ee5a700a52dc9af59c26 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 20:39:13 -0200 Subject: [PATCH 114/160] Fix appveyor/travis thinking Sublime Text is not responding --- tests/test_wrap.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_wrap.py b/tests/test_wrap.py index 30251a4..cb447c8 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -1,4 +1,5 @@ import os +import sys import re import sublime import unittest @@ -44,7 +45,11 @@ def _test_wrap(self, filename, contents, syntax): starts = re.finditer(r'^===((?:[A-Za-z0-9._-]+=[^,\n]+,?)+)?$', contents, flags=re.MULTILINE) starts = list(starts) + sys.stderr.write('\nstarts: %s, ' % len(starts)) for i, start in enumerate(starts): + # Fix appveyor/travis thinking Sublime Text is not responding + sys.stderr.write('%s. ' % (i + 1)) + sys.stderr.flush() # Get individual test substring. try: end = starts[i + 1] From 297618a8ccf50c38d45688fdfc58009dcf8bbf5f Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 20:46:38 -0200 Subject: [PATCH 115/160] Fix syntax error on .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1550266..59a3c27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,12 +61,12 @@ script: coveralls; codecov; coverage xml -o coverage.xml; - # python-codacy-coverage; fi + # python-codacy-coverage; after_success: - - echo After Success + - echo "After Success" notifications: email: false From 3e59158e7ef116577ac8fd4745bb186e4324a766 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 20:51:40 -0200 Subject: [PATCH 116/160] Removed dandling echo on appveyor.yml --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 03278f7..1c29fc3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,6 @@ build: off test_script: # run tests with test coverage report - ps: .\appveyor.ps1 "run_tests" -coverage -verbose - - echo on_finish: From a28ef6c823e1b293e54a362f3b4da6dbb9b19827 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 20 Dec 2018 20:56:30 -0200 Subject: [PATCH 117/160] Attempt to fix .travis.yml and appveyor.yml builds --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 59a3c27..f1196b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ matrix: before_install: - - curl -OL https://raw.githubusercontent.com/SublimeText/UnitTesting/master/sbin/travis.sh + - curl -OL https://raw.githubusercontent.com/evandroforks/UnitTesting/master/sbin/travis.sh - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; diff --git a/appveyor.yml b/appveyor.yml index 1c29fc3..4469df7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,7 @@ environment: install: - - ps: appveyor DownloadFile "https://raw.githubusercontent.com/SublimeText/UnitTesting/master/sbin/appveyor.ps1" + - ps: appveyor DownloadFile "https://raw.githubusercontent.com/evandroforks/UnitTesting/master/sbin/appveyor.ps1" - ps: .\appveyor.ps1 "bootstrap" -verbose - ps: pip install --disable-pip-version-check coverage codacy-coverage # install Package Control From 2caa315df057b532a42bd22645c380ead287d391 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 4 Jan 2019 14:52:03 -0200 Subject: [PATCH 118/160] Fixed .travis.yml and appveyor.yml not installing Package Control --- .travis.yml | 7 ++++--- appveyor.yml | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f1196b3..94c8f72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,8 +46,8 @@ install: # bootstrap the testing environment - sh travis.sh bootstrap - # install Package Control and package denepdencies - # - sh travis.sh install_package_control + # install Package Control and package dependencies + - sh travis.sh install_package_control script: @@ -62,7 +62,8 @@ script: codecov; coverage xml -o coverage.xml; fi - # python-codacy-coverage; + + # - python-codacy-coverage; after_success: diff --git a/appveyor.yml b/appveyor.yml index 4469df7..e99d43c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,8 +9,9 @@ install: - ps: appveyor DownloadFile "https://raw.githubusercontent.com/evandroforks/UnitTesting/master/sbin/appveyor.ps1" - ps: .\appveyor.ps1 "bootstrap" -verbose - ps: pip install --disable-pip-version-check coverage codacy-coverage + # install Package Control - # - ps: .\appveyor.ps1 "install_package_control" -verbose + - ps: .\appveyor.ps1 "install_package_control" -verbose build: off From 6c920a95aeee67a27dc8a33091eabfc522dabc35 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 4 Jan 2019 15:00:59 -0200 Subject: [PATCH 119/160] Fixed python-codacy-coverage call on .travis.yml --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 94c8f72..a7de550 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,7 +63,9 @@ script: coverage xml -o coverage.xml; fi - # - python-codacy-coverage; + # - if [ "$TRAVIS_OS_NAME" == "linux" ]; then + # python-codacy-coverage; + # fi after_success: From f7178dc5cedd90984e7ff3fd1650b54c9057ed1f Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 22 Jan 2019 14:07:33 -0200 Subject: [PATCH 120/160] Fixed Mac OS keybind for evandrocoan/WrapPlus#3 --- Default (OSX).sublime-keymap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Default (OSX).sublime-keymap b/Default (OSX).sublime-keymap index 69b0011..35a23c8 100644 --- a/Default (OSX).sublime-keymap +++ b/Default (OSX).sublime-keymap @@ -1,5 +1,5 @@ [ - { "keys": ["alt+q"], "command": "wrap_lines_plus", "context": + { "keys": ["super+alt+q"], "command": "wrap_lines_plus", "context": [ { "key": "setting.is_widget", "operator": "equal", "operand": false } ] From f80d2ebe4cc52be83b6a4a4966cb0d52de522489 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 16 Apr 2019 23:25:26 -0300 Subject: [PATCH 121/160] Fixed it putting the caret/cursor on the next line when there were whitespaces at the end of the current cursor/caret position. --- wrap_plus.py | 64 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 6f08a0b..012175c 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -749,12 +749,41 @@ def get_semantic_line_wrap_setting(self, view_settings, line_wrap_type): return is_semantic_line_wrap + def get_original_positions(self, paragraphs): + cursor_original_positions = [] + + for selection in self.view.sel(): + log(2, 'examine %r', selection) + paragraphs.extend(self._find_paragraphs(selection)) + + start = selection.begin() + reversed_index = -2 + + if start + reversed_index > 0: + sublime_region = sublime.Region(start-10, start+1) + region_substring = self.view.substr(sublime_region) + possible_newline = region_substring[-1] + + # print('region_substring %r' % region_substring, 'len', len(region_substring)) + if possible_newline in ('\n', ' '): + + while start + reversed_index > 0 \ + and abs(reversed_index) <= len(region_substring) \ + and region_substring[reversed_index] in (' ', '\t'): + # print('reversed_index', reversed_index, 'start', start) + start = start - 1 + reversed_index = reversed_index - 1 + # if abs(reversed_index) <= len(region_substring): print('next %r' % region_substring[reversed_index]) + + cursor_original_positions.append(start) + + return cursor_original_positions + def run(self, edit, width=0, line_wrap_type=None): debug_enabled = self.view.settings().get('WrapPlus.debug', False) debug_start(debug_enabled) log(2, '\n\n#########################################################################') - cursor_original_positions = [] self._width = self._determine_width(width) log(4,'wrap width = %r', self._width) @@ -763,12 +792,7 @@ def run(self, edit, width=0, line_wrap_type=None): # paragraphs is a list of (region, lines, comment_prefix) tuples. paragraphs = [] - - for selection in self.view.sel(): - log(2, 'examine %r', selection) - - paragraphs.extend(self._find_paragraphs(selection)) - cursor_original_positions.append(selection.begin()) + cursor_original_positions = self.get_original_positions(paragraphs) view_settings = self.view.settings() log(2, 'paragraphs is %r', paragraphs) @@ -793,7 +817,7 @@ def run(self, edit, width=0, line_wrap_type=None): if self.get_semantic_line_wrap_setting( view_settings, line_wrap_type ): self._width *= wrap_extension_percent - def line_wrapper_type(): + def line_wrapper_type(paragraph_lines): text = self.semantic_line_wrap( paragraph_lines, initial_indent, subsequent_indent, minimum_line_size_percent, disable_line_wrapping_by_maximum_width, balance_characters_between_line_wraps ) @@ -806,7 +830,7 @@ def line_wrapper_type(): else: - def line_wrapper_type(): + def line_wrapper_type(paragraph_lines): return self.classic_wrap_text(wrapper, paragraph_lines, initial_indent, subsequent_indent) log(4, "self._width: %s", self._width ) @@ -828,14 +852,14 @@ def line_wrapper_type(): initial_indent, subsequent_indent, paragraph_lines = self._extract_prefix( paragraph_region, paragraph_lines, required_comment_prefix) - text = line_wrapper_type() + wrapped_text = line_wrapper_type(paragraph_lines) + original_text = self.view.substr(selection) - # I can't decide if I prefer it to not make the modification - # if there is no change (and thus don't mark an unmodified - # file as modified), or if it's better to include a "non- - # change" in the undo stack. - self.view.replace(edit, selection, text) - self.print_text_replacements(text, selection) + if original_text != wrapped_text: + self.view.replace(edit, selection, wrapped_text) + log(2, 'replaced text not the same:\noriginal=%r\nnew=%r', original_text, wrapped_text) + else: + log(2, 'replaced text is the same') if after_wrap == "cursor_below": self.move_cursor_below_the_last_paragraph() @@ -1310,14 +1334,6 @@ def move_the_cursor_to_the_original_position(self, cursor_original_positions): for position in cursor_original_positions: self.view.sel().add( sublime.Region( position, position ) ) - def print_text_replacements(self, text, selection): - replaced_txt = self.view.substr(selection) - - if replaced_txt != text: - log(2, 'replaced text not the same:\noriginal=%r\nnew=%r', replaced_txt, text) - else: - log(2, 'replaced text is the same') - last_used_width = 80 From def143c0b39a174bb00e547269a04a595891e600 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 21 Apr 2019 05:41:31 -0300 Subject: [PATCH 122/160] Implemented a heuristics based on space count to fix the cursor jumping outside his original position. --- wrap_plus.py | 68 +++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 012175c..cda4076 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -757,24 +757,6 @@ def get_original_positions(self, paragraphs): paragraphs.extend(self._find_paragraphs(selection)) start = selection.begin() - reversed_index = -2 - - if start + reversed_index > 0: - sublime_region = sublime.Region(start-10, start+1) - region_substring = self.view.substr(sublime_region) - possible_newline = region_substring[-1] - - # print('region_substring %r' % region_substring, 'len', len(region_substring)) - if possible_newline in ('\n', ' '): - - while start + reversed_index > 0 \ - and abs(reversed_index) <= len(region_substring) \ - and region_substring[reversed_index] in (' ', '\t'): - # print('reversed_index', reversed_index, 'start', start) - start = start - 1 - reversed_index = reversed_index - 1 - # if abs(reversed_index) <= len(region_substring): print('next %r' % region_substring[reversed_index]) - cursor_original_positions.append(start) return cursor_original_positions @@ -792,6 +774,7 @@ def run(self, edit, width=0, line_wrap_type=None): # paragraphs is a list of (region, lines, comment_prefix) tuples. paragraphs = [] + offsets = [] cursor_original_positions = self.get_original_positions(paragraphs) view_settings = self.view.settings() @@ -856,16 +839,46 @@ def line_wrapper_type(paragraph_lines): original_text = self.view.substr(selection) if original_text != wrapped_text: + spaces_count_original = len( [ + char for char in self.view.substr( sublime.Region( selection.begin(), + cursor_original_positions[index] ) ) if char in (' ', '\t')] ) + self.view.replace(edit, selection, wrapped_text) + spaces_count_wrapped = len( [ + char for char in self.view.substr( sublime.Region( selection.begin(), + cursor_original_positions[index] ) ) if char in (' ', '\t')] ) + + # print('spaces_count_original', spaces_count_original) + # print('spaces_count_wrapped', spaces_count_wrapped) + offsets.append(spaces_count_wrapped-spaces_count_original) log(2, 'replaced text not the same:\noriginal=%r\nnew=%r', original_text, wrapped_text) + else: + offsets.append(0) log(2, 'replaced text is the same') if after_wrap == "cursor_below": self.move_cursor_below_the_last_paragraph() else: - self.move_the_cursor_to_the_original_position(cursor_original_positions) + self.move_the_cursor_to_the_original_position(cursor_original_positions, offsets) + + def move_the_cursor_to_the_original_position(self, cursor_original_positions, offsets): + self.view.sel().clear() + + for index, position in enumerate(cursor_original_positions): + self.view.sel().add( sublime.Region( position+offsets[index], position+offsets[index] ) ) + + def move_cursor_below_the_last_paragraph(self): + selection = self.view.sel() + end = selection[len(selection) - 1].end() + line = self.view.line(end) + end = min(self.view.size(), line.end() + 1) + self.view.sel().clear() + region = sublime.Region(end) + self.view.sel().add(region) + self.view.show(region) + debug_end() def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_indent, subsequent_indent): """ @@ -1317,23 +1330,6 @@ def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent return text - def move_cursor_below_the_last_paragraph(self): - selection = self.view.sel() - end = selection[len(selection) - 1].end() - line = self.view.line(end) - end = min(self.view.size(), line.end() + 1) - self.view.sel().clear() - region = sublime.Region(end) - self.view.sel().add(region) - self.view.show(region) - debug_end() - - def move_the_cursor_to_the_original_position(self, cursor_original_positions): - self.view.sel().clear() - - for position in cursor_original_positions: - self.view.sel().add( sublime.Region( position, position ) ) - last_used_width = 80 From 0ce9ca56e19da65cdfdf9b314cab78c202e0c568 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 21 Apr 2019 07:10:09 -0300 Subject: [PATCH 123/160] Implemented an alternative heuristics to keep the current position when wrapping lines with whitespace changes. --- wrap_plus.py | 53 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index cda4076..ee772cc 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -839,29 +839,56 @@ def line_wrapper_type(paragraph_lines): original_text = self.view.substr(selection) if original_text != wrapped_text: - spaces_count_original = len( [ - char for char in self.view.substr( sublime.Region( selection.begin(), - cursor_original_positions[index] ) ) if char in (' ', '\t')] ) + cut_original_text = self.view.substr( sublime.Region( selection.begin(), cursor_original_positions[index] ) ) + word_region = self.view.word(cursor_original_positions[index]) + actual_word = self.view.substr(word_region) + + distance_word_end = cursor_original_positions[index] - word_region.begin() + wrapped_text_difference = 0 + + if len(original_text) < len(wrapped_text): + wrapped_text_difference = abs( len(original_text) - len(wrapped_text) ) self.view.replace(edit, selection, wrapped_text) - spaces_count_wrapped = len( [ - char for char in self.view.substr( sublime.Region( selection.begin(), - cursor_original_positions[index] ) ) if char in (' ', '\t')] ) + replaced_region = sublime.Region( selection.begin(), word_region.end() + wrapped_text_difference ) + cut_replaced_text = self.view.substr( replaced_region ) + last_position = cut_replaced_text.rfind(actual_word) + + log(2, 'cursor_original_positions[%s]' % index, cursor_original_positions[index]) + log(2, 'cut_replaced_text', cut_replaced_text) + log(2, 'actual_word', actual_word) + log(2, 'word_region.begin', word_region.begin()) + log(2, 'word_region.end', word_region.end()) + log(2, 'last_position', last_position) + + # fallback to the original heuristic if the word is not found + if last_position > -1: + actual_position = selection.begin() + last_position + distance_word_end + offset = actual_position - cursor_original_positions[index] + + log(2, 'actual_position', actual_position, 'offset', offset ) + offsets.append( offset ) + + else: + cut_replaced_text = self.view.substr( sublime.Region( selection.begin(), word_region.begin() ) ) + spaces_count_original = len( [char for char in cut_original_text if char in (' ', '\t')] ) + spaces_count_wrapped = len( [char for char in cut_replaced_text if char in (' ', '\t')] ) + + log(2, 'spaces_count_original', spaces_count_original) + log(2, 'spaces_count_wrapped', spaces_count_wrapped) + offsets.append(spaces_count_wrapped - spaces_count_original) - # print('spaces_count_original', spaces_count_original) - # print('spaces_count_wrapped', spaces_count_wrapped) - offsets.append(spaces_count_wrapped-spaces_count_original) log(2, 'replaced text not the same:\noriginal=%r\nnew=%r', original_text, wrapped_text) else: offsets.append(0) log(2, 'replaced text is the same') - if after_wrap == "cursor_below": - self.move_cursor_below_the_last_paragraph() + if after_wrap == "cursor_below": + self.move_cursor_below_the_last_paragraph() - else: - self.move_the_cursor_to_the_original_position(cursor_original_positions, offsets) + else: + self.move_the_cursor_to_the_original_position(cursor_original_positions, offsets) def move_the_cursor_to_the_original_position(self, cursor_original_positions, offsets): self.view.sel().clear() From c028ed8f8c2862d7b387ba9dbbb3c8825ca59c4e Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 23 Apr 2019 02:25:22 -0300 Subject: [PATCH 124/160] Fixed cursor_stays option heuristics not working properly --- wrap_plus.py | 55 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index ee772cc..436cd55 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -281,6 +281,7 @@ def CONCAT(*args): # XXX: Does not handle escaped colons in field name. fields = OR(r':[^:]+:', '@[a-zA-Z]+ ') field_pattern = re.compile(r'^([ \t]*)' + fields) # rest, javadoc, jsdoc, etc +spaces_pattern = re.compile(r'^\s*$') sep_chars = '!@#$%^&*=+`~\'\":;.,?_-' sep_line = r'[{sep}]+[(?: |\t){sep}]*'.format(sep=sep_chars) @@ -837,48 +838,56 @@ def line_wrapper_type(paragraph_lines): wrapped_text = line_wrapper_type(paragraph_lines) original_text = self.view.substr(selection) + current_cursor = cursor_original_positions[index] + log(2, 'wrapped_text len', len(wrapped_text)) + log(2, 'original_text len', len(original_text)) if original_text != wrapped_text: - cut_original_text = self.view.substr( sublime.Region( selection.begin(), cursor_original_positions[index] ) ) - word_region = self.view.word(cursor_original_positions[index]) - actual_word = self.view.substr(word_region) - distance_word_end = cursor_original_positions[index] - word_region.begin() - wrapped_text_difference = 0 + while True: + word_region = self.view.word(current_cursor) + actual_word = self.view.substr(word_region).strip(' ') + log(2, 'current_cursor', current_cursor ) + log(2, 'actual_word %r' % actual_word) - if len(original_text) < len(wrapped_text): - wrapped_text_difference = abs( len(original_text) - len(wrapped_text) ) + if current_cursor < 1 or not spaces_pattern.match(actual_word): + break + current_cursor -= 1 + + cut_original_text = self.view.substr( sublime.Region( selection.begin(), word_region.end() ) ) + distance_word_end = current_cursor - word_region.begin() + log(2, 'distance_word_end', distance_word_end ) + + wrapped_text_difference = abs( len(original_text.rstrip(' ')) - len(wrapped_text) ) + 1 + log(2, 'wrapped_text_difference', wrapped_text_difference ) self.view.replace(edit, selection, wrapped_text) replaced_region = sublime.Region( selection.begin(), word_region.end() + wrapped_text_difference ) cut_replaced_text = self.view.substr( replaced_region ) - last_position = cut_replaced_text.rfind(actual_word) - - log(2, 'cursor_original_positions[%s]' % index, cursor_original_positions[index]) - log(2, 'cut_replaced_text', cut_replaced_text) - log(2, 'actual_word', actual_word) - log(2, 'word_region.begin', word_region.begin()) - log(2, 'word_region.end', word_region.end()) + last_position = cut_replaced_text.rfind( actual_word ) log(2, 'last_position', last_position) - # fallback to the original heuristic if the word is not found if last_position > -1: actual_position = selection.begin() + last_position + distance_word_end offset = actual_position - cursor_original_positions[index] - - log(2, 'actual_position', actual_position, 'offset', offset ) + log(2, 'offset', offset ) + log(2, 'actual_position', actual_position ) offsets.append( offset ) else: - cut_replaced_text = self.view.substr( sublime.Region( selection.begin(), word_region.begin() ) ) - spaces_count_original = len( [char for char in cut_original_text if char in (' ', '\t')] ) - spaces_count_wrapped = len( [char for char in cut_replaced_text if char in (' ', '\t')] ) - + # fallback to the original heuristic if the word is not found + spaces_count_original = len( [char for char in cut_original_text if spaces_pattern.match(char)] ) + spaces_count_wrapped = len( [char for char in cut_replaced_text if spaces_pattern.match(char)] ) log(2, 'spaces_count_original', spaces_count_original) log(2, 'spaces_count_wrapped', spaces_count_wrapped) - offsets.append(spaces_count_wrapped - spaces_count_original) - log(2, 'replaced text not the same:\noriginal=%r\nnew=%r', original_text, wrapped_text) + added_spaces_count = spaces_count_wrapped - spaces_count_original + log(2, 'added_spaces_count', added_spaces_count) + offsets.append(added_spaces_count) + + log(2, 'cut_original_text %r' % cut_original_text) + log(2, 'cut_replaced_text %r' % cut_replaced_text) + log(2, 'replaced text not the same!') else: offsets.append(0) From 62bdc4ded77c3a861b3f1d492309c37c17a50a7e Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 23 Apr 2019 03:28:19 -0300 Subject: [PATCH 125/160] Encapsulated the wrapped text insert on insert_wrapped_text() --- wrap_plus.py | 200 +++++++++++++++++++++++++-------------------------- 1 file changed, 99 insertions(+), 101 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 436cd55..d5351ad 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -737,8 +737,8 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): required_comment_prefix + subsequent_indent, new_lines) - def get_semantic_line_wrap_setting(self, view_settings, line_wrap_type): - is_semantic_line_wrap = view_settings.get( 'WrapPlus.semantic_line_wrap', False ) + def get_semantic_line_wrap_setting(self, line_wrap_type): + is_semantic_line_wrap = self.view_settings.get( 'WrapPlus.semantic_line_wrap', False ) if line_wrap_type: @@ -750,18 +750,6 @@ def get_semantic_line_wrap_setting(self, view_settings, line_wrap_type): return is_semantic_line_wrap - def get_original_positions(self, paragraphs): - cursor_original_positions = [] - - for selection in self.view.sel(): - log(2, 'examine %r', selection) - paragraphs.extend(self._find_paragraphs(selection)) - - start = selection.begin() - cursor_original_positions.append(start) - - return cursor_original_positions - def run(self, edit, width=0, line_wrap_type=None): debug_enabled = self.view.settings().get('WrapPlus.debug', False) debug_start(debug_enabled) @@ -775,33 +763,35 @@ def run(self, edit, width=0, line_wrap_type=None): # paragraphs is a list of (region, lines, comment_prefix) tuples. paragraphs = [] - offsets = [] - cursor_original_positions = self.get_original_positions(paragraphs) + cursor_original_positions = [] - view_settings = self.view.settings() - log(2, 'paragraphs is %r', paragraphs) + for selection in self.view.sel(): + log(2, 'examine %r', selection) + paragraphs.extend(self._find_paragraphs(selection)) + + start = selection.begin() + cursor_original_positions.append(start) - after_wrap = view_settings.get('WrapPlus.after_wrap', "cursor_below") - break_long_words = view_settings.get('WrapPlus.break_long_words', False) - break_on_hyphens = view_settings.get('WrapPlus.break_on_hyphens', False) + self.view_settings = self.view.settings() + log(2, 'paragraphs is %r', paragraphs) - wrap_extension_percent = view_settings.get('WrapPlus.semantic_wrap_extension_percent', 1.0) - minimum_line_size_percent = view_settings.get('WrapPlus.semantic_minimum_line_size_percent', 0.2) - balance_characters_between_line_wraps = view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) - disable_line_wrapping_by_maximum_width = view_settings.get('WrapPlus.semantic_disable_line_wrapping_by_maximum_width', False) + wrap_extension_percent = self.view_settings.get('WrapPlus.semantic_wrap_extension_percent', 1.0) + minimum_line_size_percent = self.view_settings.get('WrapPlus.semantic_minimum_line_size_percent', 0.2) + balance_characters_between_line_wraps = self.view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) + disable_line_wrapping_by_maximum_width = self.view_settings.get('WrapPlus.semantic_disable_line_wrapping_by_maximum_width', False) - self.maximum_words_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 - self.maximum_items_in_comma_separated_list = view_settings.get('WrapPlus.semantic_maximum_items_in_comma_separated_list', 3) + 1 + self.maximum_words_in_comma_separated_list = self.view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 + self.maximum_items_in_comma_separated_list = self.view_settings.get('WrapPlus.semantic_maximum_items_in_comma_separated_list', 3) + 1 if balance_characters_between_line_wraps: # minimum_line_size_percent = 0.0 disable_line_wrapping_by_maximum_width = True log(4, "minimum_line_size_percent: %s", minimum_line_size_percent ) - if self.get_semantic_line_wrap_setting( view_settings, line_wrap_type ): + if self.get_semantic_line_wrap_setting(line_wrap_type ): self._width *= wrap_extension_percent - def line_wrapper_type(paragraph_lines): + def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrapper): text = self.semantic_line_wrap( paragraph_lines, initial_indent, subsequent_indent, minimum_line_size_percent, disable_line_wrapping_by_maximum_width, balance_characters_between_line_wraps ) @@ -814,90 +804,98 @@ def line_wrapper_type(paragraph_lines): else: - def line_wrapper_type(paragraph_lines): + def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrapper): return self.classic_wrap_text(wrapper, paragraph_lines, initial_indent, subsequent_indent) log(4, "self._width: %s", self._width ) if paragraphs: - # Use view selections to handle shifts from the replace() command. - self.view.sel().clear() - for region, lines, comment_prefix in paragraphs: - self.view.sel().add(region) - - # Regions fetched from view.sel() will shift appropriately with - # the calls to replace(). - for index, selection in enumerate(self.view.sel()): - paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] - - wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) - wrapper.width = self._width - wrapper.expand_tabs = False - - initial_indent, subsequent_indent, paragraph_lines = self._extract_prefix( - paragraph_region, paragraph_lines, required_comment_prefix) - - wrapped_text = line_wrapper_type(paragraph_lines) - original_text = self.view.substr(selection) - current_cursor = cursor_original_positions[index] - log(2, 'wrapped_text len', len(wrapped_text)) - log(2, 'original_text len', len(original_text)) - - if original_text != wrapped_text: - - while True: - word_region = self.view.word(current_cursor) - actual_word = self.view.substr(word_region).strip(' ') - log(2, 'current_cursor', current_cursor ) - log(2, 'actual_word %r' % actual_word) - - if current_cursor < 1 or not spaces_pattern.match(actual_word): - break - current_cursor -= 1 - - cut_original_text = self.view.substr( sublime.Region( selection.begin(), word_region.end() ) ) - distance_word_end = current_cursor - word_region.begin() - log(2, 'distance_word_end', distance_word_end ) - - wrapped_text_difference = abs( len(original_text.rstrip(' ')) - len(wrapped_text) ) + 1 - log(2, 'wrapped_text_difference', wrapped_text_difference ) - - self.view.replace(edit, selection, wrapped_text) - replaced_region = sublime.Region( selection.begin(), word_region.end() + wrapped_text_difference ) - cut_replaced_text = self.view.substr( replaced_region ) - last_position = cut_replaced_text.rfind( actual_word ) - log(2, 'last_position', last_position) - - if last_position > -1: - actual_position = selection.begin() + last_position + distance_word_end - offset = actual_position - cursor_original_positions[index] - log(2, 'offset', offset ) - log(2, 'actual_position', actual_position ) - offsets.append( offset ) + self.insert_wrapped_text(edit, paragraphs, line_wrapper_type, cursor_original_positions) - else: - # fallback to the original heuristic if the word is not found - spaces_count_original = len( [char for char in cut_original_text if spaces_pattern.match(char)] ) - spaces_count_wrapped = len( [char for char in cut_replaced_text if spaces_pattern.match(char)] ) - log(2, 'spaces_count_original', spaces_count_original) - log(2, 'spaces_count_wrapped', spaces_count_wrapped) + def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_original_positions): + offsets = [] + after_wrap = self.view_settings.get('WrapPlus.after_wrap', "cursor_below") + break_long_words = self.view_settings.get('WrapPlus.break_long_words', False) + break_on_hyphens = self.view_settings.get('WrapPlus.break_on_hyphens', False) + + # Use view selections to handle shifts from the replace() command. + self.view.sel().clear() + for region, lines, comment_prefix in paragraphs: + self.view.sel().add(region) - added_spaces_count = spaces_count_wrapped - spaces_count_original - log(2, 'added_spaces_count', added_spaces_count) - offsets.append(added_spaces_count) + # Regions fetched from view.sel() will shift appropriately with + # the calls to replace(). + for index, selection in enumerate(self.view.sel()): + paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] - log(2, 'cut_original_text %r' % cut_original_text) - log(2, 'cut_replaced_text %r' % cut_replaced_text) - log(2, 'replaced text not the same!') + wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) + wrapper.width = self._width + wrapper.expand_tabs = False + + initial_indent, subsequent_indent, paragraph_lines = self._extract_prefix( + paragraph_region, paragraph_lines, required_comment_prefix) + + wrapped_text = line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrapper) + original_text = self.view.substr(selection) + current_cursor = cursor_original_positions[index] + log(2, 'wrapped_text len', len(wrapped_text)) + log(2, 'original_text len', len(original_text)) + + if original_text != wrapped_text: + + while True: + word_region = self.view.word(current_cursor) + actual_word = self.view.substr(word_region).strip(' ') + log(2, 'current_cursor', current_cursor ) + log(2, 'actual_word %r' % actual_word) + + if current_cursor < 1 or not spaces_pattern.match(actual_word): + break + current_cursor -= 1 + + cut_original_text = self.view.substr( sublime.Region( selection.begin(), word_region.end() ) ) + distance_word_end = current_cursor - word_region.begin() + log(2, 'distance_word_end', distance_word_end ) + + wrapped_text_difference = abs( len(original_text.rstrip(' ')) - len(wrapped_text) ) + 1 + log(2, 'wrapped_text_difference', wrapped_text_difference ) + + self.view.replace(edit, selection, wrapped_text) + replaced_region = sublime.Region( selection.begin(), word_region.end() + wrapped_text_difference ) + cut_replaced_text = self.view.substr( replaced_region ) + last_position = cut_replaced_text.rfind( actual_word ) + log(2, 'last_position', last_position) + + if last_position > -1: + actual_position = selection.begin() + last_position + distance_word_end + offset = actual_position - cursor_original_positions[index] + log(2, 'offset', offset ) + log(2, 'actual_position', actual_position ) + offsets.append( offset ) else: - offsets.append(0) - log(2, 'replaced text is the same') + # fallback to the original heuristic if the word is not found + spaces_count_original = len( [char for char in cut_original_text if spaces_pattern.match(char)] ) + spaces_count_wrapped = len( [char for char in cut_replaced_text if spaces_pattern.match(char)] ) + log(2, 'spaces_count_original', spaces_count_original) + log(2, 'spaces_count_wrapped', spaces_count_wrapped) - if after_wrap == "cursor_below": - self.move_cursor_below_the_last_paragraph() + added_spaces_count = spaces_count_wrapped - spaces_count_original + log(2, 'added_spaces_count', added_spaces_count) + offsets.append(added_spaces_count) + + log(2, 'cut_original_text %r' % cut_original_text) + log(2, 'cut_replaced_text %r' % cut_replaced_text) + log(2, 'replaced text not the same!') else: - self.move_the_cursor_to_the_original_position(cursor_original_positions, offsets) + offsets.append(0) + log(2, 'replaced text is the same') + + if after_wrap == "cursor_below": + self.move_cursor_below_the_last_paragraph() + + else: + self.move_the_cursor_to_the_original_position(cursor_original_positions, offsets) def move_the_cursor_to_the_original_position(self, cursor_original_positions, offsets): self.view.sel().clear() From 41be15cc5959399173f3cb046fa9cb6cc8500e07 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 23 Apr 2019 03:47:29 -0300 Subject: [PATCH 126/160] Set to _test_wrap_individual show the view contents --- tests/test_wrap.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_wrap.py b/tests/test_wrap.py index cb447c8..7585919 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -82,10 +82,11 @@ def _test_wrap_individual(self, view): sel.add(pos) while pos < view.size() - rel_end: view.run_command('wrap_lines_plus') - # Assume it advances the cursor past the wrapped section. next_pos = view.sel()[0].a if next_pos < view.size() - rel_end: - self.assertGreater(next_pos, pos) + self.assertGreater(next_pos, pos, + 'The cursor did not advanced up to the end of the file!\n' + + view.substr(sublime.Region(0, view.size()))) pos = next_pos def _tagged_regions(self, view): From 7e80b7376efbca50053c4116d1eb66a8fb6a9802 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 23 Apr 2019 04:05:57 -0300 Subject: [PATCH 127/160] Fixed cursor not moving to the next line --- wrap_plus.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index d5351ad..03d2a1b 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -768,9 +768,7 @@ def run(self, edit, width=0, line_wrap_type=None): for selection in self.view.sel(): log(2, 'examine %r', selection) paragraphs.extend(self._find_paragraphs(selection)) - - start = selection.begin() - cursor_original_positions.append(start) + cursor_original_positions.append(selection.begin()) self.view_settings = self.view.settings() log(2, 'paragraphs is %r', paragraphs) @@ -811,6 +809,11 @@ def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrappe if paragraphs: self.insert_wrapped_text(edit, paragraphs, line_wrapper_type, cursor_original_positions) + else: + after_wrap = self.view_settings.get('WrapPlus.after_wrap', "cursor_below") + if after_wrap == "cursor_below": + self.move_cursor_below_the_last_paragraph() + def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_original_positions): offsets = [] after_wrap = self.view_settings.get('WrapPlus.after_wrap', "cursor_below") @@ -894,7 +897,7 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_origin if after_wrap == "cursor_below": self.move_cursor_below_the_last_paragraph() - else: + if after_wrap == "cursor_stay": self.move_the_cursor_to_the_original_position(cursor_original_positions, offsets) def move_the_cursor_to_the_original_position(self, cursor_original_positions, offsets): From 9fc395b96d81d66b36187614f556492276ba172a Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 23 Apr 2019 04:40:26 -0300 Subject: [PATCH 128/160] Fixed index error when wrapping text inside a selection --- wrap_plus.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index 03d2a1b..0c0a1e0 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -822,9 +822,13 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_origin # Use view selections to handle shifts from the replace() command. self.view.sel().clear() - for region, lines, comment_prefix in paragraphs: + for index, others in enumerate(paragraphs): + region, lines, comment_prefix = others self.view.sel().add(region) + if index >= len(cursor_original_positions): + cursor_original_positions.append(region.begin()) + # Regions fetched from view.sel() will shift appropriately with # the calls to replace(). for index, selection in enumerate(self.view.sel()): From 4e5d507a6d31610f6c6f5b7c8a57ba3136a589f2 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 23 Apr 2019 05:08:33 -0300 Subject: [PATCH 129/160] Simplified the insert_wrapped_text code and improved its accuracy for paragraphs cursor detection. --- tests/test_extraction.py | 2 +- wrap_plus.py | 78 ++++++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/tests/test_extraction.py b/tests/test_extraction.py index 1c7cac5..0c1cdbb 100644 --- a/tests/test_extraction.py +++ b/tests/test_extraction.py @@ -62,7 +62,7 @@ def test_triple_quotes_comment(self): /// C++ comment.""" ) paragraph_results = self.wrap_plus._find_paragraphs( sublime.Region(0, 0) ) - region, paragraphs, comment_prefix = paragraph_results[0] + region, paragraphs, comment_prefix, cursor_position = paragraph_results[0] # print( "self.wrap_plus._find_paragraphs: " + str( paragraph_results ) ) self.assertEqual( '///', comment_prefix ) diff --git a/wrap_plus.py b/wrap_plus.py index 0c0a1e0..87ad0bc 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -450,6 +450,7 @@ def _find_paragraphs(self, sublime_text_region): view = self._strip_view # Loop for each paragraph (only loops once if sublime_text_region is empty). paragraph_start_pt = sublime_text_region.begin() + first_selection_to_save = paragraph_start_pt while 1: log(2, 'paragraph scanning start %r.', paragraph_start_pt,) view.set_comments(self._line_comment, self._is_block_comment, paragraph_start_pt) @@ -530,7 +531,12 @@ def _find_paragraphs(self, sublime_text_region): break paragraph_region = sublime.Region(paragraph_start_pt, paragraph_end_pt) - result.append((paragraph_region, lines, view.required_comment_prefix)) + + if first_selection_to_save: + result.append((paragraph_region, lines, view.required_comment_prefix, first_selection_to_save)) + first_selection_to_save = None + else: + result.append((paragraph_region, lines, view.required_comment_prefix, paragraph_start_pt)) if is_empty: break @@ -756,23 +762,12 @@ def run(self, edit, width=0, line_wrap_type=None): log(2, '\n\n#########################################################################') self._width = self._determine_width(width) + self.view_settings = self.view.settings() log(4,'wrap width = %r', self._width) self._determine_tab_size() self._determine_comment_style() - # paragraphs is a list of (region, lines, comment_prefix) tuples. - paragraphs = [] - cursor_original_positions = [] - - for selection in self.view.sel(): - log(2, 'examine %r', selection) - paragraphs.extend(self._find_paragraphs(selection)) - cursor_original_positions.append(selection.begin()) - - self.view_settings = self.view.settings() - log(2, 'paragraphs is %r', paragraphs) - wrap_extension_percent = self.view_settings.get('WrapPlus.semantic_wrap_extension_percent', 1.0) minimum_line_size_percent = self.view_settings.get('WrapPlus.semantic_minimum_line_size_percent', 0.2) balance_characters_between_line_wraps = self.view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) @@ -805,17 +800,26 @@ def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrappe def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrapper): return self.classic_wrap_text(wrapper, paragraph_lines, initial_indent, subsequent_indent) + # paragraphs is a list of (region, lines, comment_prefix) tuples. + paragraphs = [] + + for selection in self.view.sel(): + log(2, 'examine %r', selection) + paragraphs.extend(self._find_paragraphs(selection)) + + log(2, 'paragraphs is %r', paragraphs) log(4, "self._width: %s", self._width ) - if paragraphs: - self.insert_wrapped_text(edit, paragraphs, line_wrapper_type, cursor_original_positions) + if paragraphs: + self.insert_wrapped_text(edit, paragraphs, line_wrapper_type) else: after_wrap = self.view_settings.get('WrapPlus.after_wrap', "cursor_below") if after_wrap == "cursor_below": self.move_cursor_below_the_last_paragraph() - def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_original_positions): - offsets = [] + def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type): + new_positions = [] + after_wrap = self.view_settings.get('WrapPlus.after_wrap', "cursor_below") break_long_words = self.view_settings.get('WrapPlus.break_long_words', False) break_on_hyphens = self.view_settings.get('WrapPlus.break_on_hyphens', False) @@ -823,16 +827,13 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_origin # Use view selections to handle shifts from the replace() command. self.view.sel().clear() for index, others in enumerate(paragraphs): - region, lines, comment_prefix = others + region, lines, comment_prefix, cursor_position = others self.view.sel().add(region) - if index >= len(cursor_original_positions): - cursor_original_positions.append(region.begin()) - # Regions fetched from view.sel() will shift appropriately with # the calls to replace(). for index, selection in enumerate(self.view.sel()): - paragraph_region, paragraph_lines, required_comment_prefix = paragraphs[index] + paragraph_region, paragraph_lines, required_comment_prefix, cursor_position = paragraphs[index] wrapper = textwrap.TextWrapper(break_long_words=break_long_words, break_on_hyphens=break_on_hyphens) wrapper.width = self._width @@ -843,24 +844,23 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_origin wrapped_text = line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrapper) original_text = self.view.substr(selection) - current_cursor = cursor_original_positions[index] log(2, 'wrapped_text len', len(wrapped_text)) log(2, 'original_text len', len(original_text)) if original_text != wrapped_text: while True: - word_region = self.view.word(current_cursor) + word_region = self.view.word(cursor_position) actual_word = self.view.substr(word_region).strip(' ') - log(2, 'current_cursor', current_cursor ) + log(2, 'cursor_position', cursor_position ) log(2, 'actual_word %r' % actual_word) - if current_cursor < 1 or not spaces_pattern.match(actual_word): + if cursor_position < 1 or not spaces_pattern.match(actual_word): break - current_cursor -= 1 + cursor_position -= 1 cut_original_text = self.view.substr( sublime.Region( selection.begin(), word_region.end() ) ) - distance_word_end = current_cursor - word_region.begin() + distance_word_end = cursor_position - word_region.begin() log(2, 'distance_word_end', distance_word_end ) wrapped_text_difference = abs( len(original_text.rstrip(' ')) - len(wrapped_text) ) + 1 @@ -874,10 +874,8 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_origin if last_position > -1: actual_position = selection.begin() + last_position + distance_word_end - offset = actual_position - cursor_original_positions[index] - log(2, 'offset', offset ) - log(2, 'actual_position', actual_position ) - offsets.append( offset ) + log(2, 'new actual_position', actual_position ) + new_positions.append( actual_position ) else: # fallback to the original heuristic if the word is not found @@ -886,29 +884,29 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type, cursor_origin log(2, 'spaces_count_original', spaces_count_original) log(2, 'spaces_count_wrapped', spaces_count_wrapped) - added_spaces_count = spaces_count_wrapped - spaces_count_original - log(2, 'added_spaces_count', added_spaces_count) - offsets.append(added_spaces_count) + added_spaces_count = cursor_position + spaces_count_wrapped - spaces_count_original + log(2, 'new actual_position', added_spaces_count) + new_positions.append(added_spaces_count) log(2, 'cut_original_text %r' % cut_original_text) log(2, 'cut_replaced_text %r' % cut_replaced_text) log(2, 'replaced text not the same!') else: - offsets.append(0) + new_positions.append(cursor_position) log(2, 'replaced text is the same') if after_wrap == "cursor_below": self.move_cursor_below_the_last_paragraph() if after_wrap == "cursor_stay": - self.move_the_cursor_to_the_original_position(cursor_original_positions, offsets) + self.move_the_cursor_to_the_original_position(new_positions) - def move_the_cursor_to_the_original_position(self, cursor_original_positions, offsets): + def move_the_cursor_to_the_original_position(self, new_positions): self.view.sel().clear() - for index, position in enumerate(cursor_original_positions): - self.view.sel().add( sublime.Region( position+offsets[index], position+offsets[index] ) ) + for index, position in enumerate(new_positions): + self.view.sel().add( sublime.Region( position, position ) ) def move_cursor_below_the_last_paragraph(self): selection = self.view.sel() From 4d602a504449f8948e5bdd996ece151b6e668bb4 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 25 Apr 2019 02:23:39 -0300 Subject: [PATCH 130/160] Added to .travis.yml show_full_sublime_text_console $?; --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a7de550..0c70857 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,7 +52,7 @@ install: script: # run tests with test coverage report - - sh travis.sh run_tests --coverage + - sh travis.sh run_tests --coverage; sh travis.sh show_full_sublime_text_console $?; # testing syntax_test files # - sh travis.sh run_syntax_tests From 289f4aab469645a7369f4ba7cebf33d6b7911715 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 25 Apr 2019 23:06:39 -0300 Subject: [PATCH 131/160] Set to preserve the line last single space, when present. --- wrap_plus.py | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 87ad0bc..ea80824 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -773,6 +773,7 @@ def run(self, edit, width=0, line_wrap_type=None): balance_characters_between_line_wraps = self.view_settings.get('WrapPlus.semantic_balance_characters_between_line_wraps', False) disable_line_wrapping_by_maximum_width = self.view_settings.get('WrapPlus.semantic_disable_line_wrapping_by_maximum_width', False) + after_wrap = self.view_settings.get('WrapPlus.after_wrap', "cursor_below") self.maximum_words_in_comma_separated_list = self.view_settings.get('WrapPlus.semantic_maximum_words_in_comma_separated_list', 3) + 1 self.maximum_items_in_comma_separated_list = self.view_settings.get('WrapPlus.semantic_maximum_items_in_comma_separated_list', 3) + 1 @@ -796,31 +797,48 @@ def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrappe return "".join( text ) else: - def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrapper): return self.classic_wrap_text(wrapper, paragraph_lines, initial_indent, subsequent_indent) # paragraphs is a list of (region, lines, comment_prefix) tuples. paragraphs = [] + has_trailing_whitespace = False + selections = self.view.sel() + + if selections: + possible_last_region = self.view.word(selections[0]) + possible_last_space = self.view.substr(possible_last_region) + has_trailing_whitespace = possible_last_space \ + and not not spaces_pattern.match(possible_last_space) \ + and possible_last_space[-1] == '\n' + log(1, 'possible_last_space %r' % possible_last_space, 'has_trailing_whitespace', has_trailing_whitespace) - for selection in self.view.sel(): - log(2, 'examine %r', selection) - paragraphs.extend(self._find_paragraphs(selection)) + for selection in selections: + log(2, 'examine %r', selection) + paragraphs.extend(self._find_paragraphs(selection)) log(2, 'paragraphs is %r', paragraphs) log(4, "self._width: %s", self._width ) if paragraphs: - self.insert_wrapped_text(edit, paragraphs, line_wrapper_type) + new_positions = self.insert_wrapped_text(edit, paragraphs, line_wrapper_type) + + if after_wrap == "cursor_below": + self.move_cursor_below_the_last_paragraph() + + if after_wrap == "cursor_stay": + self.move_the_cursor_to_the_original_position( new_positions ) + + if has_trailing_whitespace: + last_position = new_positions[-1] + self.view.insert( edit, last_position, " " ) + else: - after_wrap = self.view_settings.get('WrapPlus.after_wrap', "cursor_below") if after_wrap == "cursor_below": self.move_cursor_below_the_last_paragraph() def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type): new_positions = [] - - after_wrap = self.view_settings.get('WrapPlus.after_wrap', "cursor_below") break_long_words = self.view_settings.get('WrapPlus.break_long_words', False) break_on_hyphens = self.view_settings.get('WrapPlus.break_on_hyphens', False) @@ -896,11 +914,7 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type): new_positions.append(cursor_position) log(2, 'replaced text is the same') - if after_wrap == "cursor_below": - self.move_cursor_below_the_last_paragraph() - - if after_wrap == "cursor_stay": - self.move_the_cursor_to_the_original_position(new_positions) + return new_positions def move_the_cursor_to_the_original_position(self, new_positions): self.view.sel().clear() From ddd5c941bbcf331d9e0d8b2e244148f1e3201212 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 25 Apr 2019 23:15:03 -0300 Subject: [PATCH 132/160] Fixed missed debug level enabled on wrap_plus.py --- wrap_plus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index ea80824..3cbc963 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -811,7 +811,7 @@ def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrappe has_trailing_whitespace = possible_last_space \ and not not spaces_pattern.match(possible_last_space) \ and possible_last_space[-1] == '\n' - log(1, 'possible_last_space %r' % possible_last_space, 'has_trailing_whitespace', has_trailing_whitespace) + log(2, 'possible_last_space %r' % possible_last_space, 'has_trailing_whitespace', has_trailing_whitespace) for selection in selections: log(2, 'examine %r', selection) From 0a5add82a8299edbe76ffd18f314ca28cafc7c36 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Thu, 25 Apr 2019 23:32:05 -0300 Subject: [PATCH 133/160] Only attempt to restore the trailing whitespace when changes are performed. --- wrap_plus.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 3cbc963..ecde31d 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -826,13 +826,13 @@ def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrappe if after_wrap == "cursor_below": self.move_cursor_below_the_last_paragraph() - if after_wrap == "cursor_stay": - self.move_the_cursor_to_the_original_position( new_positions ) - - if has_trailing_whitespace: - last_position = new_positions[-1] - self.view.insert( edit, last_position, " " ) + if new_positions: + if after_wrap == "cursor_stay": + self.move_the_cursor_to_the_original_position( new_positions ) + if has_trailing_whitespace: + last_position = new_positions[-1] + self.view.insert( edit, last_position, " " ) else: if after_wrap == "cursor_below": self.move_cursor_below_the_last_paragraph() From 3407cce2fbf21a12738987c6bb295a14c42a9eb7 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 26 Apr 2019 00:29:17 -0300 Subject: [PATCH 134/160] Fixed codecov.yml failing build due small diff changes https://github.com/mozilla-mobile/firefox-tv/pull/779 --- codecov.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..37186a2 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,11 @@ + +coverage: + + status: + + project: + + default: + target: null + threshold: 2% + From 2757482393cbec28ac7128f730f008c372cd6edf Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Fri, 26 Apr 2019 00:45:17 -0300 Subject: [PATCH 135/160] Fixed the usage of evandroforks instead of evandrocoan on .travis.yml and appveyor.ps1 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c70857..1030a02 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ matrix: before_install: - - curl -OL https://raw.githubusercontent.com/evandroforks/UnitTesting/master/sbin/travis.sh + - curl -OL https://raw.githubusercontent.com/evandrocoan/UnitTesting/master/sbin/travis.sh - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; diff --git a/appveyor.yml b/appveyor.yml index e99d43c..44d3ae2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,7 @@ environment: install: - - ps: appveyor DownloadFile "https://raw.githubusercontent.com/evandroforks/UnitTesting/master/sbin/appveyor.ps1" + - ps: appveyor DownloadFile "https://raw.githubusercontent.com/evandrocoan/UnitTesting/master/sbin/appveyor.ps1" - ps: .\appveyor.ps1 "bootstrap" -verbose - ps: pip install --disable-pip-version-check coverage codacy-coverage From 4e70ea6c49bf7d45284e9eaa0418779716612a28 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 04:52:26 -0300 Subject: [PATCH 136/160] Added support to do semantic line wrapping at and keyword --- tests/test_semantic_linefeed.py | 26 ++++++++++++++++++++++---- wrap_plus.py | 12 +++++++++--- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/tests/test_semantic_linefeed.py b/tests/test_semantic_linefeed.py index bb0820d..5c7511a 100644 --- a/tests/test_semantic_linefeed.py +++ b/tests/test_semantic_linefeed.py @@ -271,6 +271,13 @@ def test_semantic_line_wrap_with_numeric_comma_list_on_the_end(self): self.semantic_line_wrap( "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1", "1 2 3 4.\n5 6 7,\n1, 2, 3, 4,\n5.\n6 7 8 9 1" ) + def test_semantic_line_wrap_with_word_and_alpha_separator(self): + self.semantic_line_wrap( ["E explicar como esta nova ferramenta difere das demais já existentes,", + "e", "qual as vantagens de ter uma ferramenta."], + "E explicar como esta nova ferramenta difere das demais já existentes,\n" + "e qual as vantagens de ter uma ferramenta.", + skip_list=True ) + def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): self.semantic_line_wrap( "For all other languages you still need to find out another source code " "formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/" @@ -320,12 +327,23 @@ def test_semantic_line_wrap_with_3_items_list(self): "% DEITEL(forminhas das boas práticas)).\n" "% E deixa claro qual é o problema" ) - def semantic_line_wrap(self, initial_text, goal): + def semantic_line_wrap(self, initial_text, goal, **kwargs): + """ + Call the wrap_plus.semantic_line_wrap() function correctly. + + `initial_text` is the text to apply the line wrapping + `goal` is the expected result of this test - if isinstance( initial_text, list ): - self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text[0]], initial_text[1], initial_text[2] ) ) ) + Optionally, `initial_text` can be a list with 3 elements: + [initial_text, initial_indent, subsequent_indent] + """ + skip_list = kwargs.pop('skip_list', False) + if isinstance( initial_text, list ) and not skip_list: + self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( + [initial_text[0]], initial_text[1], initial_text[2], **kwargs ) ) ) else: - self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( [initial_text], "", "" ) ) ) + self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( + initial_text if skip_list else [initial_text], "", "", **kwargs ) ) ) diff --git a/wrap_plus.py b/wrap_plus.py index ecde31d..deac561 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -258,7 +258,7 @@ def CONCAT(*args): next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) whitespace_character = (" ", "\t") -list_separator_characters = ( ",", ";" ) +list_separator_characters = ( ",", ";", 'e', 'and') word_separator_characters = ( ".", "?", "!", ":" ) + list_separator_characters phrase_separator_characters = set( word_separator_characters ) - set( list_separator_characters ) @@ -1123,6 +1123,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, if not balance_characters_between_line_wraps: new_text.append( initial_indent ) + is_word_backboundary = False is_allowed_to_wrap = False is_possible_space = False is_flushing_comma_list = False @@ -1155,6 +1156,8 @@ def force_flush_accumulated_line(): accumulated_line_length = len( accumulated_line ) next_word_length = self.peek_next_word_length( index, text ) + is_word_backboundary = text[index-1] in whitespace_character and text[index-2] not in word_separator_characters + if is_possible_space and character in whitespace_character: continue @@ -1203,7 +1206,7 @@ def force_flush_accumulated_line(): force_flush_accumulated_line() if accumulated_line_length > minimum_line_size: - is_allowed_to_wrap = True + is_allowed_to_wrap = is_word_backboundary and character.isalpha() or not is_word_backboundary and not character.isalpha() if character in word_separator_characters and is_allowed_to_wrap \ or is_flushing_accumalated_line: @@ -1304,10 +1307,13 @@ def is_comma_separated_list(self, text, index): character = text[index] is_character_whitespace = character in whitespace_character + is_word_backboundary = text[index-1] in whitespace_character and text[index-2] not in word_separator_characters if index < text_length: + is_word_separator_character = character in list_separator_characters and ( + is_word_backboundary and character.isalpha() or not is_word_backboundary and not character.isalpha() ) + next_character = text[index+1] - is_word_separator_character = character in list_separator_characters is_next_character_whitepace = next_character in whitespace_character else: From 444b8c1c58ee9fa3a874c30ccc7dcb9c78e34066 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 04:50:16 -0300 Subject: [PATCH 137/160] Created the load_tests loader on test_extraction.py and tests/test_semantic_linefeed.py --- tests/test_extraction.py | 9 +++++++++ tests/test_semantic_linefeed.py | 8 ++++++++ unittesting.json | 1 + 3 files changed, 18 insertions(+) diff --git a/tests/test_extraction.py b/tests/test_extraction.py index 0c1cdbb..b0dc949 100644 --- a/tests/test_extraction.py +++ b/tests/test_extraction.py @@ -132,3 +132,12 @@ def test_markdown_triple_quotes_line_start(self): ] ```""" ), self.get_view_contents() ) + +def load_tests(loader, standard_tests, pattern): + suite = unittest.TestSuite() + suite.addTest( PrefixStrippingViewUnitTests( 'test_markdown_triple_quotes_line_start' ) ) + return suite + +# Comment this to run individual Unit Tests +load_tests = None + diff --git a/tests/test_semantic_linefeed.py b/tests/test_semantic_linefeed.py index 5c7511a..24f6950 100644 --- a/tests/test_semantic_linefeed.py +++ b/tests/test_semantic_linefeed.py @@ -347,3 +347,11 @@ def semantic_line_wrap(self, initial_text, goal, **kwargs): initial_text if skip_list else [initial_text], "", "", **kwargs ) ) ) +def load_tests(loader, standard_tests, pattern): + suite = unittest.TestSuite() + suite.addTest( SemanticLineWrapUnitTests( 'test_semantic_line_wrap_with_word_and_alpha_separator' ) ) + return suite + +# Comment this to run individual Unit Tests +load_tests = None + diff --git a/unittesting.json b/unittesting.json index 77c2ae5..9576b8f 100644 --- a/unittesting.json +++ b/unittesting.json @@ -1,6 +1,7 @@ { "tests_dir" : "tests", "pattern" : "test_*.py", + // "pattern" : "test_semantic_linefeed.py", "async": true, "deferred": false, "verbosity": 2, From 1f22780963f25e7e0a487d04d6083ab8a2a06088 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 05:41:43 -0300 Subject: [PATCH 138/160] Fixed latex comments on open brackets {% breaking the wrapping --- tests/wrap_tests/test.tex | 16 ++++++++++++++++ wrap_plus.py | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/wrap_tests/test.tex b/tests/wrap_tests/test.tex index b730274..1686597 100644 --- a/tests/wrap_tests/test.tex +++ b/tests/wrap_tests/test.tex @@ -4,6 +4,22 @@ --- This is a test. This is a test. This is a test. This is a test. % This is a comment === +\lang{% + Moreover, explain the differences for other softwares and the benefits + of a unique tool, instead of several heavily different ones. +}{% + E explicar como esta nova ferramenta difere das demais já existentes, + e qual as vantagens de ter uma ferramenta. +} +--- +\lang{% + Moreover, explain the differences for other softwares and the benefits of + a unique tool, instead of several heavily different ones. +}{% + E explicar como esta nova ferramenta difere das demais já existentes, e + qual as vantagens de ter uma ferramenta. +} +=== This is an example of a citation starting on a new line \cite{Newton1687} --- diff --git a/wrap_plus.py b/wrap_plus.py index deac561..d12b4b1 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -254,7 +254,9 @@ def CONCAT(*args): return '(?:' + ''.join(args) + ')' -blank_line_pattern = re.compile(r'(?:^[\t \{\}\n]*(?:````?.*)?)$|(?:.*"""\\?$)') +first_group = lambda x: r"(?:^[\t \{\}\n]%s(?:````?.*)?)" % x +blank_line_pattern = re.compile( r'({}$|{}(?:[%/].*)?$|(?:.*"""\\?$))'.format( first_group('*'), first_group('+') ) ) +# print('pattern', blank_line_pattern.pattern) next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) whitespace_character = (" ", "\t") From 427ef3b5871ef6858fa05a89f87c9d67c3421e7c Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 06:05:18 -0300 Subject: [PATCH 139/160] Simplified the tests/test_semantic_linefeed.py assertions interface --- tests/test_semantic_linefeed.py | 67 +++++++++++++++------------------ wrap_plus.py | 2 +- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/tests/test_semantic_linefeed.py b/tests/test_semantic_linefeed.py index 24f6950..bf5e1eb 100644 --- a/tests/test_semantic_linefeed.py +++ b/tests/test_semantic_linefeed.py @@ -231,103 +231,105 @@ def is_comma_separated_list(self, text, index, goal): # semantic_line_wrap Unit Tests def test_semantic_line_wrap_simple_sentence(self): - self.semantic_line_wrap( "1", "1" ) + self.semantic_line_wrap( [ "1" ], "1" ) def test_semantic_line_wrap_simple_sentence_with_single_comma(self): - self.semantic_line_wrap( "which will take, you quite some time", + self.semantic_line_wrap( [ "which will take, you quite some time" ], "which will take,\nyou quite some time" ) def test_semantic_line_wrap_simple_sentence_with_dual_comma(self): self.wrap_plus.maximum_items_in_comma_separated_list = 4 - self.semantic_line_wrap( "which will take, you, quite some time", + self.semantic_line_wrap( [ "which will take, you, quite some time" ], "which will take, you, quite some time" ) def test_semantic_line_wrap_simple_sentence_with_dual_comma_with_3_items_minimum(self): self.wrap_plus.maximum_items_in_comma_separated_list = 3 - self.semantic_line_wrap( "which will take, you, quite some time", + self.semantic_line_wrap( [ "which will take, you, quite some time" ], "which will take,\nyou, quite some time" ) def test_semantic_line_wrap_long_word(self): - self.semantic_line_wrap( "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime", + self.semantic_line_wrap( [ "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ], "quitesometimequitesometimequitesometimequitesometimequitesometimequitesometimequitesometime" ) def test_semantic_line_wrap_ending_with_comma_list(self): - self.semantic_line_wrap( "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc.", + self.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc." ], "you still only configuring a few languages closely related.\nOn this case,\nC, C++, Java, Pawn,\netc." ) def test_semantic_line_wrap_ending_with_trailling_comma_on_list(self): - self.semantic_line_wrap( "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc,", + self.semantic_line_wrap( [ "you still only configuring a few languages closely related. On this case, C, C++, Java, Pawn, etc," ], "you still only configuring a few languages closely related.\nOn this case,\nC, C++, Java, Pawn, etc," ) def test_semantic_line_wrap_with_comma_list_on_the_middle(self): - self.semantic_line_wrap( "which will not more take, you quite oh the time, some time, more time, the time, per time", + self.semantic_line_wrap( [ "which will not more take, you quite oh the time, some time, more time, the time, per time" ], "which will not more take,\nyou quite oh the time,\nsome time, more time, the time, per time" ) def test_semantic_line_wrap_with_comma_list_on_the_end(self): - self.semantic_line_wrap( "few languages close related. On this case, C, C++, Java, Pawn, etc. more over break this line", + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, etc. more over break this line" ], "few languages close related.\nOn this case,\nC, C++, Java, Pawn,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_numeric_comma_list_on_the_end(self): - self.semantic_line_wrap( "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1", + self.semantic_line_wrap( [ "1 2 3 4. 5 6 7, 1, 2, 3, 4, 5. 6 7 8 9 1" ], "1 2 3 4.\n5 6 7,\n1, 2, 3, 4,\n5.\n6 7 8 9 1" ) def test_semantic_line_wrap_with_word_and_alpha_separator(self): - self.semantic_line_wrap( ["E explicar como esta nova ferramenta difere das demais já existentes,", + self.semantic_line_wrap( [ "E explicar como esta nova ferramenta difere das demais já existentes,", "e", "qual as vantagens de ter uma ferramenta."], "E explicar como esta nova ferramenta difere das demais já existentes,\n" - "e qual as vantagens de ter uma ferramenta.", - skip_list=True ) + "e qual as vantagens de ter uma ferramenta." ) def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): - self.semantic_line_wrap( "For all other languages you still need to find out another source code " + self.semantic_line_wrap( [ "For all other languages you still need to find out another source code " "formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/" - "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}", - + "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" + ], "For all other languages you still need to find out another source code " "formatter\ntool,\nwhich will be certainly\nlimited\\footnote{\\url{https://stackoverflow.com/" "questions/31438377/how-can-i-get-eclipse-to-wrap-lines-after-a-period-instead-of-before}}" ) def test_semantic_line_wrap_with_80_characters(self): - self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "few languages close related.\nOn this case,\nC, C++, Javas, Pawn, if, you, already, had, written, the, program, assure,\neverything, is, under, versioning, control, system, and, broke, everything,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_79_characters(self): - self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Java, Pawn, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "few languages close related.\nOn this case,\nC, C++, Java, Pawn, if, you, already, had, written, the, program, assure,\neverything, is, under, versioning, control, system, and, broke, everything,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_81_characters(self): - self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, program, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line" ], "few languages close related.\nOn this case,\nC, C++, Javas, Pawns, if, you, already, had, written, the, program, assure,\neverything, is, under, versioning, control, system, and, broke, everything,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_81_characters_on_list_flushing(self): - self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line", "", "" ], + self.semantic_line_wrap( [ "few languages close related. On this case, C, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure, everything, is, under, versioning, control, system, and, broke, everything, etc. more over break this line"], "few languages close related.\nOn this case,\nC, C++, Javas, Pawns, if, you, already, had, written, the, programs, assure,\neverything, is, under, versioning, control, system, and, broke, everything,\netc.\nmore over break this line" ) def test_semantic_line_wrap_with_initial_indentation(self): self.semantic_line_wrap( [ "For all other languages you still need to find out another source code f tool, " - "which will be certainly limited and still need to configure all over again.", " ", " " ], + "which will be certainly limited and still need to configure all over again." + ], " For all other languages you still need to find out another source code f\n" " tool,\n" - " which will be certainly limited and still need to configure all over again." ) + " which will be certainly limited and still need to configure all over again.", " ", " " ) def test_semantic_line_wrap_with_0_items_list(self): self.wrap_plus.maximum_items_in_comma_separated_list = 3 self.semantic_line_wrap( [ "% as boas práticas de programação (code clean, GOF, DEITEL" - "(forminhas das boas práticas)). E deixa claro qual é o problema", "", "% " ], + "(forminhas das boas práticas)). E deixa claro qual é o problema" ], "% as boas práticas de programação (code clean,\n" "% GOF,\n" "% DEITEL(forminhas das boas práticas)).\n" - "% E deixa claro qual é o problema" ) + "% E deixa claro qual é o problema", + "", "% " ) def test_semantic_line_wrap_with_3_items_list(self): self.wrap_plus.maximum_items_in_comma_separated_list = 4 self.semantic_line_wrap( [ "% as boas práticas de programação (code clean, GOF, DEITEL" - "(forminhas das boas práticas)). E deixa claro qual é o problema", "", "% " ], + "(forminhas das boas práticas)). E deixa claro qual é o problema"], "% as boas práticas de programação (code clean, GOF,\n" "% DEITEL(forminhas das boas práticas)).\n" - "% E deixa claro qual é o problema" ) + "% E deixa claro qual é o problema", + "", "% " ) - def semantic_line_wrap(self, initial_text, goal, **kwargs): + def semantic_line_wrap(self, initial_text, goal, *args, **kwargs): """ Call the wrap_plus.semantic_line_wrap() function correctly. @@ -337,19 +339,12 @@ def semantic_line_wrap(self, initial_text, goal, **kwargs): Optionally, `initial_text` can be a list with 3 elements: [initial_text, initial_indent, subsequent_indent] """ - skip_list = kwargs.pop('skip_list', False) - if isinstance( initial_text, list ) and not skip_list: - self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( - [initial_text[0]], initial_text[1], initial_text[2], **kwargs ) ) ) - - else: - self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( - initial_text if skip_list else [initial_text], "", "", **kwargs ) ) ) + self.assertEqual( goal, "".join( self.wrap_plus.semantic_line_wrap( initial_text, *args, **kwargs ) ) ) def load_tests(loader, standard_tests, pattern): suite = unittest.TestSuite() - suite.addTest( SemanticLineWrapUnitTests( 'test_semantic_line_wrap_with_word_and_alpha_separator' ) ) + suite.addTest( SemanticLineWrapUnitTests( 'test_semantic_line_wrap_with_alpha_separator_and_brackets' ) ) return suite # Comment this to run individual Unit Tests diff --git a/wrap_plus.py b/wrap_plus.py index d12b4b1..b9a6935 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1107,7 +1107,7 @@ def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum log(4, "calculate_lines_count, lines_count: %s", lines_count ) return lines_count, new_line_length - def semantic_line_wrap(self, paragraph_lines, initial_indent, subsequent_indent, + def semantic_line_wrap(self, paragraph_lines, initial_indent="", subsequent_indent="", minimum_line_size_percent=0.0, disable_line_wrapping_by_maximum_width=False, balance_characters_between_line_wraps=False): """ From 18937c5f81895ca8200df3e2958153941d7d9648 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 14:49:26 -0300 Subject: [PATCH 140/160] Fixed multi character word separator not working --- tests/test_semantic_linefeed.py | 7 +++++++ wrap_plus.py | 31 +++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/tests/test_semantic_linefeed.py b/tests/test_semantic_linefeed.py index bf5e1eb..73f24a3 100644 --- a/tests/test_semantic_linefeed.py +++ b/tests/test_semantic_linefeed.py @@ -277,6 +277,13 @@ def test_semantic_line_wrap_with_word_and_alpha_separator(self): "E explicar como esta nova ferramenta difere das demais já existentes,\n" "e qual as vantagens de ter uma ferramenta." ) + def test_semantic_line_wrap_with_multiword_and_alpha_separator(self): + self.semantic_line_wrap( [ "E explicar como esta nova ferramenta difere das demais já existentes,", + "and", "qual as vantagens de ter uma ferramenta."], + "E explicar como esta nova ferramenta difere das demais já existentes,\n" + "and qual as vantagens de ter uma ferramenta." + ) + def test_semantic_line_wrap_with_long_word_at_comma_list_end(self): self.semantic_line_wrap( [ "For all other languages you still need to find out another source code " "formatter tool, which will be certainly limited\\footnote{\\url{https://stackoverflow.com/" diff --git a/wrap_plus.py b/wrap_plus.py index b9a6935..32fc59c 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -260,7 +260,8 @@ def CONCAT(*args): next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) whitespace_character = (" ", "\t") -list_separator_characters = ( ",", ";", 'e', 'and') +alpha_separator_characters = ('e', 'and') +list_separator_characters = ( ",", ";") + alpha_separator_characters word_separator_characters = ( ".", "?", "!", ":" ) + list_separator_characters phrase_separator_characters = set( word_separator_characters ) - set( list_separator_characters ) @@ -1157,8 +1158,7 @@ def force_flush_accumulated_line(): for index, character in enumerate( text ): accumulated_line_length = len( accumulated_line ) next_word_length = self.peek_next_word_length( index, text ) - - is_word_backboundary = text[index-1] in whitespace_character and text[index-2] not in word_separator_characters + is_word_backboundary = self.is_word_separator_alpha(index, text) if is_possible_space and character in whitespace_character: continue @@ -1290,6 +1290,29 @@ def peek_next_word_length(self, index, text): return 0 + def is_word_separator_alpha(self, index, text): + character = text[index] + is_the_separator_end = False + + for separator in alpha_separator_characters: + + if character == separator[-1]: + separator_length = len(separator) + + if index > separator_length: + + for separator_index, separator_character in enumerate( reversed(separator) ): + + if separator_character != text[index - separator_index]: + break + + # This else is only run when the break statement is not raised or the list is empty! + else: + return ( text[index-separator_length] in whitespace_character + and text[index-separator_length-1] not in word_separator_characters ) + + return False + def is_comma_separated_list(self, text, index): """ return if the next characters form a command separated list @@ -1309,7 +1332,7 @@ def is_comma_separated_list(self, text, index): character = text[index] is_character_whitespace = character in whitespace_character - is_word_backboundary = text[index-1] in whitespace_character and text[index-2] not in word_separator_characters + is_word_backboundary = self.is_word_separator_alpha(index, text) if index < text_length: is_word_separator_character = character in list_separator_characters and ( From 187fe3726ee8281b6a07e511403b6d42562a3de2 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 16:16:39 -0300 Subject: [PATCH 141/160] Set to test_wrap.py create multiple test classes instead of running all tests inside one big test. --- tests/test_wrap.py | 253 ++++++++++++++++++++++++++------------------- 1 file changed, 146 insertions(+), 107 deletions(-) diff --git a/tests/test_wrap.py b/tests/test_wrap.py index 7585919..760ba24 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -24,115 +24,154 @@ 'WrapPlus.skip_range': False, # Workaround for a bug. } +has_failures = [] -class TestWrap(unittest.TestCase): - - def test_wrap(self): - base = os.path.join(plugin_path, 'tests', 'wrap_tests') - to_test = os.listdir(base) - for filename in to_test: - abspath = os.path.join(base, filename) - contents = open(abspath, encoding='utf8').read() - contents = contents.replace('\r\n', '\n') - i = contents.find('\n') - syntax = contents[:i] - contents = contents[i + 1:] - assert contents.startswith('==='), 'bad file %r' % (filename,) - self._test_wrap(filename, contents, syntax) - - def _test_wrap(self, filename, contents, syntax): +def make_wrap_tests(): + base = os.path.join(plugin_path, 'tests', 'wrap_tests') + to_test = os.listdir(base) + + for filename in to_test: + abspath = os.path.join(base, filename) + contents = open(abspath, encoding='utf8').read() + contents = contents.replace('\r\n', '\n') + index = contents.find('\n') + syntax = contents[:index] + contents = contents[index + 1:] + assert contents.startswith('==='), 'bad file %r' % (filename,) + + # _test_wrap(filename, contents, syntax) # Split test file into separate tests. starts = re.finditer(r'^===((?:[A-Za-z0-9._-]+=[^,\n]+,?)+)?$', contents, flags=re.MULTILINE) starts = list(starts) - sys.stderr.write('\nstarts: %s, ' % len(starts)) - for i, start in enumerate(starts): - # Fix appveyor/travis thinking Sublime Text is not responding - sys.stderr.write('%s. ' % (i + 1)) - sys.stderr.flush() - # Get individual test substring. - try: - end = starts[i + 1] - except IndexError: - end = len(contents) - else: - end = end.start(0) - test_str = contents[start.end(0) + 1:end] - orig, expected = re.split('^---\n', test_str, flags=re.MULTILINE) - # Get optional settings. - settings = {} - if start.group(1): - for setting in start.group(1).split(','): - setting_name, value = setting.split('=') - settings[setting_name] = eval(value) - # Open a new view to run the test in. - self._wrap_with_scratch(filename, orig, expected, syntax, settings, - self._test_wrap_individual) - if not settings.get('WrapPlus.skip_range', False): - self._wrap_with_scratch(filename, orig, expected, syntax, settings, - self._test_wrap_ranges) - - def _test_wrap_individual(self, view): - # Test wrapping every line. - for r in self._tagged_regions(view): - pos = r[0] - rel_end = view.size() - r[1] - sel = view.sel() - sel.clear() - sel.add(pos) - while pos < view.size() - rel_end: - view.run_command('wrap_lines_plus') - next_pos = view.sel()[0].a - if next_pos < view.size() - rel_end: - self.assertGreater(next_pos, pos, - 'The cursor did not advanced up to the end of the file!\n' - + view.substr(sublime.Region(0, view.size()))) - pos = next_pos - - def _tagged_regions(self, view): - if not view.find('', 0): - yield (0, view.size()) - return - - while True: - start = view.find('', 0) - if not start: - return - view.sel().clear() - view.sel().add(start) - view.run_command('left_delete') - end = view.find('', 0) - view.sel().clear() - view.sel().add(end) - view.run_command('left_delete') - yield (start.a, end.a) - - def _test_wrap_ranges(self, view): - regions = [sublime.Region(*r) for r in self._tagged_regions(view)] - view.sel().clear() - view.sel().add_all(regions) - view.run_command('wrap_lines_plus') - - def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): - window = sublime.active_window() - view = window.new_file() - view.set_scratch(True) - view.set_syntax_file(syntax) - # Update settings. - view_settings = view.settings() - bad_keys = set(settings.keys()) - set(DEFAULT_SETTINGS.keys()) - self.assertEqual(bad_keys, set()) - for setting_name, value in DEFAULT_SETTINGS.items(): - value = settings.get(setting_name, value) - if value == UNSET: - view_settings.erase(setting_name) - else: - view_settings.set(setting_name, value) - view.run_command('append', {'characters': contents}) - f(view) - actual = view.substr(sublime.Region(0, view.size())) - if actual != expected: - raise AssertionError('Wrapping did not match: %s %r\n%s---Expected:\n%s---' % ( - filename, settings, actual, expected)) - window.focus_view(view) - window.run_command('close_file') + sys.stderr.write('Creating %s tests from %s <%s>...\n' % (len(starts), filename, syntax)) + + for index, start in enumerate(starts): + + class IntegrationTests(unittest.TestCase): + # https://stackoverflow.com/questions/4414234/getting-pythons-unittest-results-in-a-teardown-method + old_failureException = unittest.TestCase.failureException + + @property + def failureException(self): + has_failures.append('fail') + return self.old_failureException + + def setUp(self): + # https://stackoverflow.com/questions/23741133/if-condition-in-setup-ignore-test + if has_failures: + self.skipTest("An test has failed, skipping everything else!") + + def test_thing(self): + # Fix appveyor/travis thinking Sublime Text is not responding + sys.stderr.write('%s. %s <%s>' % (self.index + 1, self.filename, self.syntax)) + sys.stderr.flush() + # Get individual test substring. + try: + end = self.starts[self.index + 1] + except IndexError: + end = len(self.contents) + else: + end = end.start(0) + test_str = self.contents[self.start.end(0) + 1:end] + orig, expected = re.split('^---\n', test_str, flags=re.MULTILINE) + # Get optional settings. + settings = {} + if self.start.group(1): + for setting in self.start.group(1).split(','): + setting_name, value = setting.split('=') + settings[setting_name] = eval(value) + # Open a new view to run the test in. + self._wrap_with_scratch(self.filename, orig, expected, self.syntax, settings, + self._test_wrap_individual) + if not settings.get('WrapPlus.skip_range', False): + self._wrap_with_scratch(self.filename, orig, expected, self.syntax, settings, + self._test_wrap_ranges) + + def _test_wrap_individual(self, view): + # Test wrapping every line. + for r in self._tagged_regions(view): + pos = r[0] + rel_end = view.size() - r[1] + sel = view.sel() + sel.clear() + sel.add(pos) + while pos < view.size() - rel_end: + view.run_command('wrap_lines_plus') + next_pos = view.sel()[0].a + if next_pos < view.size() - rel_end: + self.assertGreater(next_pos, pos, + 'The cursor did not advanced up to the end of the file!\n' + + view.substr(sublime.Region(0, view.size()))) + pos = next_pos + + def _tagged_regions(self, view): + if not view.find('', 0): + yield (0, view.size()) + return + + while True: + start = view.find('', 0) + if not start: + return + view.sel().clear() + view.sel().add(start) + view.run_command('left_delete') + end = view.find('', 0) + view.sel().clear() + view.sel().add(end) + view.run_command('left_delete') + yield (start.a, end.a) + + def _test_wrap_ranges(self, view): + regions = [sublime.Region(*r) for r in self._tagged_regions(view)] + view.sel().clear() + view.sel().add_all(regions) + view.run_command('wrap_lines_plus') + + def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): + window = sublime.active_window() + view = window.new_file() + view.set_scratch(True) + view.set_syntax_file(syntax) + # Update settings. + view_settings = view.settings() + bad_keys = set(settings.keys()) - set(DEFAULT_SETTINGS.keys()) + self.assertEqual(bad_keys, set()) + for setting_name, value in DEFAULT_SETTINGS.items(): + value = settings.get(setting_name, value) + if value == UNSET: + view_settings.erase(setting_name) + else: + view_settings.set(setting_name, value) + view.run_command('append', {'characters': contents}) + f(view) + actual = view.substr(sublime.Region(0, view.size())) + if actual != expected: + raise AssertionError('Wrapping did not match: %s %r\n%s---Expected:\n%s---' % ( + filename, settings, actual, expected)) + window.focus_view(view) + window.run_command('close_file') + + test_name = "".join( character for character in filename if character.isalpha() ) + _NAME = "Integration{}{:03d}Tests".format( test_name.title(), index ) + IntegrationTests.__name__ = _NAME + IntegrationTests.index = index + IntegrationTests.start = start + IntegrationTests.starts = starts + IntegrationTests.filename = filename + IntegrationTests.syntax = syntax + IntegrationTests.contents = contents + globals()[_NAME] = IntegrationTests + +make_wrap_tests() + +def load_tests(loader, standard_tests, pattern): + suite = unittest.TestSuite() + # See _NAME above to get the test class name pattern + suite.addTest( IntegrationTesttex001Tests( 'test_thing' ) ) + suite.addTest( IntegrationTesttxt020Tests( 'test_thing' ) ) + return suite + +# Comment this to run individual Unit Tests +load_tests = None From 11935b9f5a5b56edeaff93022f743a3226839d33 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 20:03:21 -0300 Subject: [PATCH 142/160] Implemented support to alpha comma separated lists and created an integration test for it. --- tests/test_semantic_linefeed.py | 3 ++- tests/test_wrap.py | 31 +++++++++++++++++++++--- tests/wrap_tests/semantic_test.tex | 19 +++++++++++++++ wrap_plus.py | 38 +++++++++++++++++------------- 4 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 tests/wrap_tests/semantic_test.tex diff --git a/tests/test_semantic_linefeed.py b/tests/test_semantic_linefeed.py index 73f24a3..6c0ac90 100644 --- a/tests/test_semantic_linefeed.py +++ b/tests/test_semantic_linefeed.py @@ -315,7 +315,8 @@ def test_semantic_line_wrap_with_initial_indentation(self): ], " For all other languages you still need to find out another source code f\n" " tool,\n" - " which will be certainly limited and still need to configure all over again.", " ", " " ) + " which will be certainly limited and\n" + " still need to configure all over again.", " ", " " ) def test_semantic_line_wrap_with_0_items_list(self): self.wrap_plus.maximum_items_in_comma_separated_list = 3 diff --git a/tests/test_wrap.py b/tests/test_wrap.py index 760ba24..369ec25 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -24,6 +24,27 @@ 'WrapPlus.skip_range': False, # Workaround for a bug. } +SEMANTIC_SETTINGS = { + 'word_wrap': False, + 'wrap_width': 0, + 'rulers': [], + 'tab_size': 4, + 'translate_tabs_to_spaces': False, + 'WrapPlus.break_long_words': False, + 'WrapPlus.break_on_hyphens': False, + 'WrapPlus.after_wrap': 'cursor_below', + 'WrapPlus.semantic_line_wrap': True, + "WrapPlus.semantic_balance_characters_between_line_wraps": True, + "WrapPlus.semantic_minimum_line_size_percent": 0.0, + "WrapPlus.semantic_wrap_extension_percent": 1.3, + "WrapPlus.semantic_maximum_items_in_comma_separated_list": 3, + "WrapPlus.semantic_maximum_words_in_comma_separated_list": 3, + "WrapPlus.semantic_disable_line_wrapping_by_maximum_width": False, + 'WrapPlus.include_line_endings': 'auto', + 'WrapPlus.wrap_width': UNSET, + 'WrapPlus.skip_range': False, # Workaround for a bug. +} + has_failures = [] def make_wrap_tests(): @@ -138,12 +159,15 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): view_settings = view.settings() bad_keys = set(settings.keys()) - set(DEFAULT_SETTINGS.keys()) self.assertEqual(bad_keys, set()) - for setting_name, value in DEFAULT_SETTINGS.items(): + + settings_type = SEMANTIC_SETTINGS.items() if filename.startswith('semantic') else DEFAULT_SETTINGS.items() + for setting_name, value in settings_type: value = settings.get(setting_name, value) if value == UNSET: view_settings.erase(setting_name) else: view_settings.set(setting_name, value) + view.run_command('append', {'characters': contents}) f(view) actual = view.substr(sublime.Region(0, view.size())) @@ -169,8 +193,9 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): def load_tests(loader, standard_tests, pattern): suite = unittest.TestSuite() # See _NAME above to get the test class name pattern - suite.addTest( IntegrationTesttex001Tests( 'test_thing' ) ) - suite.addTest( IntegrationTesttxt020Tests( 'test_thing' ) ) + # suite.addTest( IntegrationTesttex001Tests( 'test_thing' ) ) + # suite.addTest( IntegrationTesttxt020Tests( 'test_thing' ) ) + suite.addTest( IntegrationSemantictesttex000Tests( 'test_thing' ) ) return suite # Comment this to run individual Unit Tests diff --git a/tests/wrap_tests/semantic_test.tex b/tests/wrap_tests/semantic_test.tex new file mode 100644 index 0000000..a3f88ca --- /dev/null +++ b/tests/wrap_tests/semantic_test.tex @@ -0,0 +1,19 @@ +Packages/LaTeX/LaTeX.sublime-syntax +=== +\lang{% + Moreover, explain the differences for other softwares and the benefits + of a unique tool, instead of several heavily different ones. +}{% + E explicar como esta nova ferramenta difere das demais já existentes, e qual as vantagens de ter + uma ferramenta. +} +--- +\lang{% + Moreover, + explain the differences for other softwares and + the benefits of a unique tool, + instead of several heavily different ones. +}{% + E explicar como esta nova ferramenta difere das demais já existentes, + e qual as vantagens de ter uma ferramenta. +} diff --git a/wrap_plus.py b/wrap_plus.py index 32fc59c..514ce63 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -261,7 +261,7 @@ def CONCAT(*args): next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) whitespace_character = (" ", "\t") alpha_separator_characters = ('e', 'and') -list_separator_characters = ( ",", ";") + alpha_separator_characters +list_separator_characters = ( ",", ";") word_separator_characters = ( ".", "?", "!", ":" ) + list_separator_characters phrase_separator_characters = set( word_separator_characters ) - set( list_separator_characters ) @@ -1126,7 +1126,6 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent="", subsequent_inde if not balance_characters_between_line_wraps: new_text.append( initial_indent ) - is_word_backboundary = False is_allowed_to_wrap = False is_possible_space = False is_flushing_comma_list = False @@ -1158,7 +1157,6 @@ def force_flush_accumulated_line(): for index, character in enumerate( text ): accumulated_line_length = len( accumulated_line ) next_word_length = self.peek_next_word_length( index, text ) - is_word_backboundary = self.is_word_separator_alpha(index, text) if is_possible_space and character in whitespace_character: continue @@ -1208,9 +1206,9 @@ def force_flush_accumulated_line(): force_flush_accumulated_line() if accumulated_line_length > minimum_line_size: - is_allowed_to_wrap = is_word_backboundary and character.isalpha() or not is_word_backboundary and not character.isalpha() + is_allowed_to_wrap = True - if character in word_separator_characters and is_allowed_to_wrap \ + if self.is_word_separator_alpha(index, text, word_separator_characters) and is_allowed_to_wrap \ or is_flushing_accumalated_line: if index + 2 < text_length: @@ -1220,7 +1218,7 @@ def force_flush_accumulated_line(): if not is_flushing_comma_list: - if character in list_separator_characters: + if self.is_word_separator_alpha(index, text, list_separator_characters): is_comma_separated_list, comma_list_end_point, comma_separated_list_items_count = \ self.is_comma_separated_list( text, index ) @@ -1229,11 +1227,14 @@ def force_flush_accumulated_line(): if comma_separated_list_items_count < self.maximum_items_in_comma_separated_list: is_comma_separated_list = False - elif character in word_separator_characters: + elif self.is_word_separator_alpha(index, text, word_separator_characters): comma_list_size = -1 is_comma_separated_list = False - log(4, "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)", index, comma_list_size, self.maximum_items_in_comma_separated_list ) + log(4, "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)", + index, comma_list_size, self.maximum_items_in_comma_separated_list, + 'is_comma', is_comma_separated_list, + 'is_flushing', is_flushing_accumalated_line ) if ( is_comma_separated_list \ and comma_list_size > -1 ) \ and not is_flushing_comma_list \ @@ -1290,10 +1291,11 @@ def peek_next_word_length(self, index, text): return 0 - def is_word_separator_alpha(self, index, text): + def is_word_separator_alpha(self, index, text, checklisk): character = text[index] - is_the_separator_end = False + is_word_backboundary = False + log(4, 'startswith', index, text[index:]) for separator in alpha_separator_characters: if character == separator[-1]: @@ -1302,16 +1304,22 @@ def is_word_separator_alpha(self, index, text): if index > separator_length: for separator_index, separator_character in enumerate( reversed(separator) ): + log(4, 'checking', separator_character, text[index - separator_index] ) if separator_character != text[index - separator_index]: break # This else is only run when the break statement is not raised or the list is empty! else: - return ( text[index-separator_length] in whitespace_character - and text[index-separator_length-1] not in word_separator_characters ) + backboundary = ( + text[index-separator_length] in whitespace_character + and text[index-separator_length-1] not in word_separator_characters + and spaces_pattern.match( text[index+1] ) + ) + is_word_backboundary = backboundary and character.isalpha() or not backboundary and not character.isalpha() - return False + log(4, 'is_word_backboundary', is_word_backboundary ) + return is_word_backboundary or character in checklisk def is_comma_separated_list(self, text, index): """ @@ -1332,11 +1340,9 @@ def is_comma_separated_list(self, text, index): character = text[index] is_character_whitespace = character in whitespace_character - is_word_backboundary = self.is_word_separator_alpha(index, text) if index < text_length: - is_word_separator_character = character in list_separator_characters and ( - is_word_backboundary and character.isalpha() or not is_word_backboundary and not character.isalpha() ) + is_word_separator_character = self.is_word_separator_alpha(index, text, list_separator_characters) next_character = text[index+1] is_next_character_whitepace = next_character in whitespace_character From ccbd58175d14fa1610398f76cf91a47bf8353de4 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 20:53:40 -0300 Subject: [PATCH 143/160] Adjusted the wrap_plus.py logging messages consistently --- wrap_plus.py | 100 +++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 514ce63..afc99da 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -50,7 +50,7 @@ def debug_start(enabled): def debug_end(): if debug_enabled > 1: - log(1, 'Total time: %.3f', time.time() - time_start) + log(1, 'Total time %.3f', time.time() - time_start) class PrefixStrippingView(object): @@ -114,7 +114,7 @@ def set_comments(self, line_comments, block_comment, point): # Determine if point is inside a "line comment". # Only whitespace is allowed to the left of the line comment. is_generic_config = "source.genconfig" in scope_name - log(2, "line_comments: %s", line_comments ) + log(2, "line_comments %s", line_comments) # When using the generic syntax, the Sublime Text plugin `Default.comment` will return # the default syntax comment prefix `#` instead of the actual line prefix @@ -131,7 +131,7 @@ def set_comments(self, line_comments, block_comment, point): for line_comment, is_block_comment in extended_prefixes: line_comment = line_comment.rstrip() - log(2, "line_comment: %s, line_stripped: %s", line_comment, line_stripped ) + log(2, "line_comment %s line_stripped %s", line_comment, line_stripped) if line_stripped.startswith(line_comment): @@ -276,7 +276,7 @@ def CONCAT(*args): field_start = r'(?:[:@])' # rest, javadoc, jsdoc, etc. new_paragraph_pattern_string = r'^[\t ]*' + OR(lettered_list, bullet_list, field_start, r'\{') -log(4, "pattern: " + new_paragraph_pattern_string ) +log(4, "pattern " + new_paragraph_pattern_string) new_paragraph_pattern = re.compile(new_paragraph_pattern_string) space_prefix_pattern = re.compile(r'^[ \t]*') @@ -366,11 +366,11 @@ def _is_paragraph_break(self, line_region, line, pure=False): return True if pure: pure_break = pure_break_pattern.match(line) is not None - log(2, 'pure_break:', pure_break) + log(2, 'pure_break', pure_break) return pure_break else: normal_break = break_pattern.match(line) is not None - log(2, 'normal_break:', normal_break) + log(2, 'normal_break', normal_break) return normal_break def _is_blank_line(self, line): @@ -399,7 +399,7 @@ def _find_paragraph_start(self, point): # Check if this line is the start of a paragraph. log(2, 'is the start of a paragraph?') if self._is_paragraph_start(current_line_region, current_line): - log(2, 'yes, current_line is paragraph start: %r', current_line,) + log(2, 'yes, current_line is paragraph start %r', current_line,) break log(2, 'no') # Check if the previous line is a "break" separator. @@ -438,7 +438,7 @@ def _find_paragraphs(self, sublime_text_region): :returns: A list of (region, lines, comment_prefix) of each paragraph. """ result = [] - log(2, 'find paragraphs sublime_text_region=%r', sublime_text_region,) + log(2, 'sublime_text_region=%r', sublime_text_region,) if sublime_text_region.empty(): is_empty = True view_min = 0 @@ -510,7 +510,7 @@ def _find_paragraphs(self, sublime_text_region): regex_match = re.search('([ \t]+$)', region_substring) if regex_match: end_pt -= len(regex_match.group(1)) - log(2, 'non-comment contents are: %r', region_substring) + log(2, 'non-comment contents are %r', region_substring) paragraph_end_pt = end_pt lines.append(region_substring) # Skip over the comment. @@ -573,14 +573,14 @@ def _determine_width(self, width): :returns: The maximum line width. """ - log(4, "_determine_width, width: %s", width ) + log( 4, "width %s", width ) if width == 0 and self.view.settings().get('wrap_width'): try: width = int(self.view.settings().get('wrap_width')) except TypeError: pass - log(4, "_determine_width, before get('rulers'), width: %s", width ) + log( 4, "before get('rulers') width %s", width ) if width == 0 and self.view.settings().get('rulers'): # try and guess the wrap width from the ruler, if any try: @@ -590,7 +590,7 @@ def _determine_width(self, width): except TypeError: pass - log(4, "_determine_width, before get('WrapPlus.wrap_width', width): %s", width ) + log( 4, "before get('WrapPlus.wrap_width') %s", width ) if width == 0: width = self.view.settings().get('WrapPlus.wrap_width', width) @@ -675,7 +675,7 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): regex_match = list_pattern.match(first_line) if regex_match: initial_indent = first_line[0:regex_match.end()] - log(2, 'setting initial_indent:', initial_indent) + log(2, 'setting initial_indent', initial_indent) stripped_prefix = initial_indent.lstrip() leading_whitespace = initial_indent[:len(initial_indent) - len(stripped_prefix)] @@ -685,7 +685,7 @@ def _extract_prefix(self, paragraph_region, lines, required_comment_prefix): if regex_match: # The spaces in front of the field start. initial_indent = regex_match.group(1) - log(2, 'setting initial_indent:', initial_indent) + log(2, 'setting initial_indent', initial_indent) if len(lines) > 1: # How to handle subsequent lines. regex_match = space_prefix_pattern.match(lines[1]) @@ -784,7 +784,7 @@ def run(self, edit, width=0, line_wrap_type=None): # minimum_line_size_percent = 0.0 disable_line_wrapping_by_maximum_width = True - log(4, "minimum_line_size_percent: %s", minimum_line_size_percent ) + log( 4, "minimum_line_size_percent %s", minimum_line_size_percent ) if self.get_semantic_line_wrap_setting(line_wrap_type ): self._width *= wrap_extension_percent @@ -796,7 +796,7 @@ def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrappe if balance_characters_between_line_wraps: text = self.balance_characters_between_line_wraps( wrapper, text, initial_indent, subsequent_indent ) - log(4, 'run, text: ' + "".join( text ) ) + log( 4, 'run, text %r', "".join( text ) ) return "".join( text ) else: @@ -820,8 +820,8 @@ def line_wrapper_type(paragraph_lines, initial_indent, subsequent_indent, wrappe log(2, 'examine %r', selection) paragraphs.extend(self._find_paragraphs(selection)) - log(2, 'paragraphs is %r', paragraphs) - log(4, "self._width: %s", self._width ) + log( 2, 'paragraphs is %r', paragraphs ) + log( 4, "self._width %s", self._width ) if paragraphs: new_positions = self.insert_wrapped_text(edit, paragraphs, line_wrapper_type) @@ -873,7 +873,7 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type): while True: word_region = self.view.word(cursor_position) actual_word = self.view.substr(word_region).strip(' ') - log(2, 'cursor_position', cursor_position ) + log(2, 'cursor_position', cursor_position) log(2, 'actual_word %r' % actual_word) if cursor_position < 1 or not spaces_pattern.match(actual_word): @@ -882,10 +882,10 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type): cut_original_text = self.view.substr( sublime.Region( selection.begin(), word_region.end() ) ) distance_word_end = cursor_position - word_region.begin() - log(2, 'distance_word_end', distance_word_end ) + log(2, 'distance_word_end', distance_word_end) wrapped_text_difference = abs( len(original_text.rstrip(' ')) - len(wrapped_text) ) + 1 - log(2, 'wrapped_text_difference', wrapped_text_difference ) + log(2, 'wrapped_text_difference', wrapped_text_difference) self.view.replace(edit, selection, wrapped_text) replaced_region = sublime.Region( selection.begin(), word_region.end() + wrapped_text_difference ) @@ -895,7 +895,7 @@ def insert_wrapped_text(self, edit, paragraphs, line_wrapper_type): if last_position > -1: actual_position = selection.begin() + last_position + distance_word_end - log(2, 'new actual_position', actual_position ) + log(2, 'new actual_position', actual_position) new_positions.append( actual_position ) else: @@ -985,7 +985,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind break - log(4, "\nShrinking the lines..." ) + log( 4, "\nShrinking the lines..." ) new_lines_backup = list( new_lines ) if self.is_there_line_over_the_wrap_limit( new_lines ): @@ -1015,7 +1015,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind new_text.append( subsequent_indent ) new_text.extend( new_lines ) - log(4, "balance_characters_between_line_wraps, new_text: %s", new_text ) + log( 4, "new_text %s", new_text ) return new_text def is_line_bellow_half_wrap_limit(self, new_lines, subsequent_indent_length): @@ -1050,7 +1050,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li for step in range( 1, lines_count + 1 ): new_line_length = math.ceil( line_length / step ) - log(4, "_split_lines, new_line_length: %d, lines_count: %d", new_line_length, lines_count ) + log( 4, "new_line_length %d lines_count %d", new_line_length, lines_count ) if new_line_length > maximum_line_width: continue @@ -1058,13 +1058,13 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li else: break - log(4, "_split_lines, maximum_line_width: %d, new_width: %d (%f)", maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) + log( 4, "maximum_line_width %d new_width %d (%f)", maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) wrapper.width = math.ceil( new_line_length * middle_of_the_line_increment_percent ) - log(4, "_split_lines, line: " + line ) + log( 4, "line " + line ) wrapped_line = wrapper.fill( line ) - log(4, "_split_lines, wrapped_line: " + wrapped_line ) + log( 4, "wrapped_line " + wrapped_line ) wrapped_lines = wrapped_line.split( "\n" ) # Add again the removed `\n` character due the `split` statement @@ -1079,7 +1079,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li new_lines.append( fixed_wrapped_lines ) - log(4, "_split_lines, new_lines: %s", new_lines ) + log( 4, "new_lines %s", new_lines ) return new_lines def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum_line_width): @@ -1099,13 +1099,13 @@ def calculate_lines_count(self, line, initial_indent, subsequent_indent, maximum while last_line_length != new_line_length \ and lines_count < line_length: - log(4, "calculate_lines_count, new_line_length: %s", new_line_length ) + log( 4, "new_line_length %s", new_line_length ) last_line_length = new_line_length lines_count = math.ceil( last_line_length / maximum_line_width ) new_line_length = ( lines_count - 1 ) * subsequent_indent_length + line_length - log(4, "calculate_lines_count, lines_count: %s", lines_count ) + log( 4, "lines_count %s", lines_count ) return lines_count, new_line_length def semantic_line_wrap(self, paragraph_lines, initial_indent="", subsequent_indent="", @@ -1136,7 +1136,7 @@ def semantic_line_wrap(self, paragraph_lines, initial_indent="", subsequent_inde text_length = len(text) minimum_line_size = int( self._width * minimum_line_size_percent ) - log(4, "minimum_line_size: %s", minimum_line_size ) + log( 4, "minimum_line_size %s", minimum_line_size ) indent_length = initial_indent_length accumulated_line = "" @@ -1148,7 +1148,7 @@ def force_flush_accumulated_line(): nonlocal index nonlocal is_flushing_accumalated_line - log(4, "semantic_line_wrap, Flushing accumulated_line... next_word_length: %d", next_word_length ) + log( 4, "Flushing accumulated_line... next_word_length %d", next_word_length ) is_flushing_accumalated_line = True # Current character is a whitespace, but it must the the next, so fix the index @@ -1171,7 +1171,7 @@ def force_flush_accumulated_line(): comma_list_size -= 1 last_comma_list_size = comma_list_size + 1 - log(4, "semantic_line_wrap, is_flushing, index: %d, accumulated_line_length: %d, comma_list_size: %d, comma_list_end_point: %d, character: %s", index, accumulated_line_length, comma_list_size, comma_list_end_point, character ) + log( 4, "is_flushing, index %d accumulated_line_length %d comma_list_size %d comma_list_end_point %d character %s", index, accumulated_line_length, comma_list_size, comma_list_end_point, character ) if not is_flushing_accumalated_line: if not disable_line_wrapping_by_maximum_width \ @@ -1198,7 +1198,7 @@ def force_flush_accumulated_line(): is_flushing_comma_list = False is_comma_separated_list = False - log(4, "semantic_line_wrap, index: %d, character: %s ", index, character ) + log( 4, "%d %s ", index, character ) if not disable_line_wrapping_by_maximum_width \ and not is_flushing_accumalated_line \ and accumulated_line_length + next_word_length + indent_length > self._width: @@ -1231,7 +1231,7 @@ def force_flush_accumulated_line(): comma_list_size = -1 is_comma_separated_list = False - log(4, "semantic_line_wrap, index: %3d, comma_list_size: %d (%d)", + log( 4, "index %3d comma_list_size %d maximum_size %d", index, comma_list_size, self.maximum_items_in_comma_separated_list, 'is_comma', is_comma_separated_list, 'is_flushing', is_flushing_accumalated_line ) @@ -1251,7 +1251,7 @@ def force_flush_accumulated_line(): accumulated_line = "".join( [accumulated_line, character, "\n", ( "" if balance_characters_between_line_wraps else subsequent_indent ) ] ) - log(4, "semantic_line_wrap, accumulated_line flush: %r", accumulated_line ) + log( 4, "accumulated_line flush %r", accumulated_line ) new_text.append( accumulated_line ) accumulated_line = "" @@ -1277,7 +1277,7 @@ def force_flush_accumulated_line(): if len( accumulated_line ): new_text.append(accumulated_line) - log(4, "semantic_line_wrap, new_text: %s", new_text ) + log( 4, "new_text %s", new_text ) return new_text def peek_next_word_length(self, index, text): @@ -1286,7 +1286,7 @@ def peek_next_word_length(self, index, text): if match: next_word = match.group(0) - log(4, "peek_next_word_length: %s", next_word ) + log( 4, "%r %s", next_word, len( next_word ) ) return len( next_word ) return 0 @@ -1295,16 +1295,13 @@ def is_word_separator_alpha(self, index, text, checklisk): character = text[index] is_word_backboundary = False - log(4, 'startswith', index, text[index:]) for separator in alpha_separator_characters: if character == separator[-1]: separator_length = len(separator) if index > separator_length: - for separator_index, separator_character in enumerate( reversed(separator) ): - log(4, 'checking', separator_character, text[index - separator_index] ) if separator_character != text[index - separator_index]: break @@ -1314,11 +1311,12 @@ def is_word_separator_alpha(self, index, text, checklisk): backboundary = ( text[index-separator_length] in whitespace_character and text[index-separator_length-1] not in word_separator_characters - and spaces_pattern.match( text[index+1] ) + and not not spaces_pattern.match( text[index+1] ) ) is_word_backboundary = backboundary and character.isalpha() or not backboundary and not character.isalpha() + log( 4, separator, is_word_backboundary, backboundary ) + break - log(4, 'is_word_backboundary', is_word_backboundary ) return is_word_backboundary or character in checklisk def is_comma_separated_list(self, text, index): @@ -1326,7 +1324,7 @@ def is_comma_separated_list(self, text, index): return if the next characters form a command separated list return 0 if False, otherwise the `text` index where the command separated list ended """ - log(4, "is_comma_separated_list, index: %d", index ) + log( 4, "index %d", index ) comma_list_end_point = -1 # A word list has at least 2 items. For example: start 1, 2, 3 words @@ -1356,7 +1354,7 @@ def is_comma_separated_list(self, text, index): if is_character_whitespace and not is_next_character_whitepace: words_counter += 1 - log(4, "is_comma_separated_list, index: %d, words_counter: %d, character: %s, next_character: %s", index, words_counter, character, next_character ) + log( 4, "%d char %s next %s words %d", index, character, next_character, words_counter ) if is_word_separator_character and is_next_character_whitepace: if 0 < words_counter < self.maximum_words_in_comma_separated_list: @@ -1373,10 +1371,10 @@ def is_comma_separated_list(self, text, index): words_counter = 0 if comma_list_end_point > -1: - log(4, "is_comma_separated_list (True), comma_list_end_point: %d, comma_separated_list_items_count: %d", comma_list_end_point, comma_separated_list_items_count ) + log( 4, "True, end_point %d items_count %d", comma_list_end_point, comma_separated_list_items_count ) return True, comma_list_end_point, comma_separated_list_items_count - log(4, "is_comma_separated_list (False), comma_list_end_point: %d, comma_separated_list_items_count: %d", 0, 0 ) + log( 4, "False, end_point %d items_count %d", 0, 0 ) return False, 0, 0 def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent_indent): @@ -1406,9 +1404,9 @@ def classic_wrap_text(self, wrapper, paragraph_lines, initial_indent, subsequent lines = text.splitlines() if initial_indent != orig_initial_indent: - log(2, 'fix tabs %r', lines[0]) + log( 2, 'fix tabs %r', lines[0]) lines[0] = orig_initial_indent + lines[0][len(initial_indent):] - log(2, 'new line is %r', lines[0]) + log( 2, 'new line is %r', lines[0]) if subsequent_indent != orig_subsequent_indent: @@ -1429,7 +1427,7 @@ def run(self, edit, line_wrap_type=None): self.line_wrap_type = line_wrap_type view = sublime.active_window().show_input_panel( - 'Provide wrapping width:', str( last_used_width ), + 'Provide wrapping width', str( last_used_width ), self.input_package, None, None ) view.run_command("select_all") From 7fafc9485bb8792954e98d71313a21aacf762288 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 1 May 2019 21:08:27 -0300 Subject: [PATCH 144/160] Deprecated the fix for appveyor/travis thinking Sublime Text is not responding and set the test name pattern to snake case. --- tests/test_wrap.py | 19 +++++++++++-------- unittesting.json | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/test_wrap.py b/tests/test_wrap.py index 369ec25..b3b687d 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -84,9 +84,6 @@ def setUp(self): self.skipTest("An test has failed, skipping everything else!") def test_thing(self): - # Fix appveyor/travis thinking Sublime Text is not responding - sys.stderr.write('%s. %s <%s>' % (self.index + 1, self.filename, self.syntax)) - sys.stderr.flush() # Get individual test substring. try: end = self.starts[self.index + 1] @@ -177,8 +174,16 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): window.focus_view(view) window.run_command('close_file') - test_name = "".join( character for character in filename if character.isalpha() ) - _NAME = "Integration{}{:03d}Tests".format( test_name.title(), index ) + test_name = [] + for character in filename: + if character.isalpha(): + test_name.append(character.lower()) + else: + test_name.append('_') + + test_name = "".join(test_name) + _NAME = "integration_{}_{:d}_tests".format( test_name, index ) + IntegrationTests.__name__ = _NAME IntegrationTests.index = index IntegrationTests.start = start @@ -193,9 +198,7 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): def load_tests(loader, standard_tests, pattern): suite = unittest.TestSuite() # See _NAME above to get the test class name pattern - # suite.addTest( IntegrationTesttex001Tests( 'test_thing' ) ) - # suite.addTest( IntegrationTesttxt020Tests( 'test_thing' ) ) - suite.addTest( IntegrationSemantictesttex000Tests( 'test_thing' ) ) + suite.addTest( integration_test_txt_15_tests( 'test_thing' ) ) return suite # Comment this to run individual Unit Tests diff --git a/unittesting.json b/unittesting.json index 9576b8f..0b1fcdb 100644 --- a/unittesting.json +++ b/unittesting.json @@ -1,6 +1,7 @@ { "tests_dir" : "tests", "pattern" : "test_*.py", + // "pattern" : "test_wrap.py", // "pattern" : "test_semantic_linefeed.py", "async": true, "deferred": false, From 96f759e5d6cceaf57ccf7c323791d30006e89289 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 4 May 2019 00:24:41 -0300 Subject: [PATCH 145/160] Fixed line wrapping with words greater than maximum line width --- tests/test_extraction.py | 5 +++ tests/test_semantic_linefeed.py | 37 ++++++++++++++++++- tests/test_wrap.py | 5 +-- tests/wrap_tests/semantic_test.tex | 23 ++++++++++++ wrap_plus.py | 57 +++++++++++++++++++++++++----- 5 files changed, 115 insertions(+), 12 deletions(-) diff --git a/tests/test_extraction.py b/tests/test_extraction.py index b0dc949..36184f7 100644 --- a/tests/test_extraction.py +++ b/tests/test_extraction.py @@ -30,6 +30,7 @@ def setUp(self): # make sure we have a window to work with settings = sublime.load_settings("Preferences.sublime-settings") + self.close_windows_when_empty = settings.get("close_windows_when_empty", False) settings.set("close_windows_when_empty", False) def tearDown(self): @@ -38,6 +39,10 @@ def tearDown(self): self.view.window().focus_view(self.view) self.view.window().run_command("close_file") + if self.close_windows_when_empty: + settings = sublime.load_settings("Preferences.sublime-settings") + settings.set("close_windows_when_empty", self.close_windows_when_empty) + def setText(self, string, start_point=0): self.view.run_command("append", {"characters": wrap_text( string ) }) diff --git a/tests/test_semantic_linefeed.py b/tests/test_semantic_linefeed.py index 6c0ac90..ac0dafa 100644 --- a/tests/test_semantic_linefeed.py +++ b/tests/test_semantic_linefeed.py @@ -136,6 +136,38 @@ def test_balance_characters_between_line_wraps_with_comment_indentation_balance( self.wrap_plus.balance_characters_between_line_wraps( self.wrapper, input_text, "% ", "% " ) ) + def test_balance_characters_with_verybig_word_on_line_at_100(self): + self._test_balance_characters_with_verybig_word_on_line_at(100) + + def test_balance_characters_with_verybig_word_on_line_at_80(self): + self._test_balance_characters_with_verybig_word_on_line_at(80) + + def _test_balance_characters_with_verybig_word_on_line_at(self, wrapsize): + self.wrap_plus._width = wrapsize + input_text = \ + [ + 'Já que para compartilhar código e\n', + 'trabalhar em times de forma eficiente,\n', + 'é essential utilizar\\hyp{}se um sistema de versionamento\\footnote{\\url{http://www.codeservedcold.com/version-control-importance/}} que permita gerente de projetos e\n', + 'os próprios programadores' + ] + expected_list = \ + [ + '', + 'Já que para compartilhar código e\n', + '', + 'trabalhar em times de forma eficiente,\n', + '', + 'é essential utilizar\\hyp{}se um sistema de\n', + 'versionamento\\footnote{\\url{http://www.codeservedcold.com/version-control-importance/}}\n', + 'que permita gerente de projetos e\n', + '', + 'os próprios programadores' + ] + self.assertEqual( expected_list, + self.wrap_plus.balance_characters_between_line_wraps( + self.wrapper, input_text, "", "" ) ) + def test_balance_characters_between_line_wraps_commented_line(self): indent = "% " self.wrap_plus._width = 80 @@ -352,7 +384,10 @@ def semantic_line_wrap(self, initial_text, goal, *args, **kwargs): def load_tests(loader, standard_tests, pattern): suite = unittest.TestSuite() - suite.addTest( SemanticLineWrapUnitTests( 'test_semantic_line_wrap_with_alpha_separator_and_brackets' ) ) + # suite.addTest( SemanticLineWrapUnitTests( 'test_semantic_line_wrap_with_3_items_list' ) ) + # suite.addTest( LineBalancingUnitTests( 'test_balance_characters_with_verybig_word_on_line_at_80' ) ) + # suite.addTest( LineBalancingUnitTests( 'test_balance_characters_with_verybig_word_on_line_at_100' ) ) + suite.addTest( LineBalancingUnitTests( 'test_balance_characters_between_line_wraps_with_long_subsequent_indentation' ) ) return suite # Comment this to run individual Unit Tests diff --git a/tests/test_wrap.py b/tests/test_wrap.py index b3b687d..357986d 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -182,7 +182,7 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): test_name.append('_') test_name = "".join(test_name) - _NAME = "integration_{}_{:d}_tests".format( test_name, index ) + _NAME = "integration_{}_{:02d}_tests".format( test_name, index ) IntegrationTests.__name__ = _NAME IntegrationTests.index = index @@ -198,7 +198,8 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): def load_tests(loader, standard_tests, pattern): suite = unittest.TestSuite() # See _NAME above to get the test class name pattern - suite.addTest( integration_test_txt_15_tests( 'test_thing' ) ) + # suite.addTest( integration_test_txt_15_tests( 'test_thing' ) ) + suite.addTest( integration_semantic_test_tex_02_tests( 'test_thing' ) ) return suite # Comment this to run individual Unit Tests diff --git a/tests/wrap_tests/semantic_test.tex b/tests/wrap_tests/semantic_test.tex index a3f88ca..21fc300 100644 --- a/tests/wrap_tests/semantic_test.tex +++ b/tests/wrap_tests/semantic_test.tex @@ -17,3 +17,26 @@ E explicar como esta nova ferramenta difere das demais já existentes, e qual as vantagens de ter uma ferramenta. } +=== +Já que para compartilhar código e trabalhar em times de forma eficiente, é essential +utilizar\hyp{}se um sistema de +versionamento\footnote{\url{http://www.codeservedcold.com/version-control-importance/}} que permita +o gerente de projetos e os próprios programadores teste +--- +Já que para compartilhar código e +trabalhar em times de forma eficiente, +é essential utilizar\hyp{}se um sistema de +versionamento\footnote{\url{http://www.codeservedcold.com/version-control-importance/}} +que permita o gerente de projetos e +os próprios programadores teste +=== +Já que para compartilhar código e trabalhar em times de forma eficiente, é essential +utilizar\hyp{}se um sistema de +versionamento\footnote{\url{http://www.codeservedcold.com/version-control-importance/}} que permita +o gerente de projetos e os próprios programadores +--- +Já que para compartilhar código e +trabalhar em times de forma eficiente, +é essential utilizar\hyp{}se um sistema de +versionamento\footnote{\url{http://www.codeservedcold.com/version-control-importance/}} que +permita o gerente de projetos e os próprios programadores diff --git a/wrap_plus.py b/wrap_plus.py index afc99da..144c6b8 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -29,6 +29,8 @@ def is_quoted_string(scope_region, scope_name): debug_enabled = 1 # log = getLogger(debug_enabled, "wrap_plus", "wrapplus.txt", mode='w') log = getLogger(debug_enabled, "wrap_plus") +# log = getLogger( debug_enabled, "wrap_plus", "wrapplus.txt" ) +# log = getLogger( debug_enabled, "wrap_plus", "wrapplus.txt", mode='w', time=False, msecs=False, tick=False ) def plugin_unloaded(): @@ -276,7 +278,7 @@ def CONCAT(*args): field_start = r'(?:[:@])' # rest, javadoc, jsdoc, etc. new_paragraph_pattern_string = r'^[\t ]*' + OR(lettered_list, bullet_list, field_start, r'\{') -log(4, "pattern " + new_paragraph_pattern_string) +log(4, "pattern", new_paragraph_pattern_string) new_paragraph_pattern = re.compile(new_paragraph_pattern_string) space_prefix_pattern = re.compile(r'^[ \t]*') @@ -285,6 +287,7 @@ def CONCAT(*args): fields = OR(r':[^:]+:', '@[a-zA-Z]+ ') field_pattern = re.compile(r'^([ \t]*)' + fields) # rest, javadoc, jsdoc, etc spaces_pattern = re.compile(r'^\s*$') +not_spaces_pattern = re.compile(r'[^ ]+') sep_chars = '!@#$%^&*=+`~\'\":;.,?_-' sep_line = r'[{sep}]+[(?: |\t){sep}]*'.format(sep=sep_chars) @@ -945,6 +948,7 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind wrapper.initial_indent = "" wrapper.subsequent_indent = subsequent_indent subsequent_indent_length = len( subsequent_indent ) + log( 4, 'text_lines', text_lines ) # `decrement_percent` must be stronger than 1.1, i.e., 1.1*1.1 = 1.21*0.9 = 1.089 < 1.1 # otherwise this could immediately fail as the last line length would already be @@ -985,16 +989,16 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind break - log( 4, "\nShrinking the lines..." ) + log.clean( 4, "" ) + log( 4, "Shrinking the lines... '%s'", new_lines ) new_lines_backup = list( new_lines ) if self.is_there_line_over_the_wrap_limit( new_lines ): - decrement_percent = increment_percent * DECREMENT_VALUE new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, decrement_percent )[0] # Try to decrease the maximum width until create a trailing new line - while ( self.is_there_line_over_the_wrap_limit(new_lines) \ + while ( self.is_there_line_over_the_wrap_limit( new_lines ) \ or self.is_line_bellow_half_wrap_limit( new_lines, subsequent_indent_length ) ) \ and decrement_percent > 0.4: @@ -1004,7 +1008,12 @@ def balance_characters_between_line_wraps(self, wrapper, text_lines, initial_ind # If still there are lines over the limit, it means some line has some very big word # or some very big indentation, then there is nothing we can do other than discard # the results. Comment this out, and you will see the Unit Tests failing with it. - if self.is_there_line_over_the_wrap_limit( new_lines ): + lonely_word_line = self.is_there_lonely_word_line( new_lines ) + + if lonely_word_line: + new_lines = self._split_lines( wrapper, [text_lines[index]], self._width, lonely_word_line )[0] + + elif self.is_there_line_over_the_wrap_limit( new_lines ): new_lines = new_lines_backup if index < 1: @@ -1035,6 +1044,34 @@ def is_there_line_over_the_wrap_limit(self, new_lines): return False + def is_there_lonely_word_line(self, new_lines): + """ + Check whether there is some line with a single big word only. + + If so, it means, we must to stop wrapping with traditional line balancing algorithm. + """ + for new_line in new_lines: + longest = -1 + line_length = len( new_line ) + line_percent_size = math.ceil( line_length / self._width ) + + for match in not_spaces_pattern.finditer( new_line ): + start, end = match.span() + length = end - start + + if length > longest: + longest = length + + new_width = 0.95 if longest > self._width else line_percent_size + line_limit = self._width * 0.8 + log( 4, 'line_percent_size', line_percent_size, 'line_length', line_length, + 'longest', longest, 'new_width', new_width, 'line_limit', line_limit ) + + if longest > line_limit: + return new_width + + return False + def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_line_increment_percent=1): """ (input) text_lines: [' This is my very long line which will wrap near its end,\n'] @@ -1058,13 +1095,14 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li else: break - log( 4, "maximum_line_width %d new_width %d (%f)", maximum_line_width, math.ceil( new_line_length * middle_of_the_line_increment_percent ), middle_of_the_line_increment_percent ) - wrapper.width = math.ceil( new_line_length * middle_of_the_line_increment_percent ) + new_width = math.ceil( new_line_length * middle_of_the_line_increment_percent ) + log( 4, "maximum_line_width %d new_width %d (%f)", maximum_line_width, new_width, middle_of_the_line_increment_percent ) - log( 4, "line " + line ) + log( 4, "line %r", line ) + wrapper.width = new_width wrapped_line = wrapper.fill( line ) - log( 4, "wrapped_line " + wrapped_line ) + log( 4, "wrapped_line %r", wrapped_line ) wrapped_lines = wrapped_line.split( "\n" ) # Add again the removed `\n` character due the `split` statement @@ -1079,6 +1117,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li new_lines.append( fixed_wrapped_lines ) + log.clean("") log( 4, "new_lines %s", new_lines ) return new_lines From 37d81232f1175d867875bdbdb11fac3b0abd5d6a Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 4 May 2019 17:26:01 -0300 Subject: [PATCH 146/160] Removed duplicated log getter line on wrap_plus.py --- wrap_plus.py | 1 - 1 file changed, 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index 144c6b8..44b65b8 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -27,7 +27,6 @@ def is_quoted_string(scope_region, scope_name): time_start = 0 debug_enabled = 1 -# log = getLogger(debug_enabled, "wrap_plus", "wrapplus.txt", mode='w') log = getLogger(debug_enabled, "wrap_plus") # log = getLogger( debug_enabled, "wrap_plus", "wrapplus.txt" ) # log = getLogger( debug_enabled, "wrap_plus", "wrapplus.txt", mode='w', time=False, msecs=False, tick=False ) From ff6f16d676e0415a13a9c0002433b6d2f738bfa4 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 7 May 2019 09:08:33 -0300 Subject: [PATCH 147/160] Added debug messages for _is_real_numbered_list() --- wrap_plus.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 44b65b8..543f416 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -51,7 +51,7 @@ def debug_start(enabled): def debug_end(): if debug_enabled > 1: - log(1, 'Total time %.3f', time.time() - time_start) + log( 2, 'Total time %.3f', time.time() - time_start ) class PrefixStrippingView(object): @@ -324,35 +324,42 @@ def _is_real_numbered_list(self, line_region, line, limit=10, indent=False): # in a loop over the input and also contains a loop over the input. # indent tracks whether we came from an indented line if limit == 0: + log( 2, 'limit', limit ) return True regex_match = numbered_list_pattern.search(line) if regex_match and regex_match.group(1) == '1': + log( 2, 'regex_match %r', regex_match.group(1), '%r' % line ) return True prev_line_region, prev_line = self._strip_view.prev_line(line_region) if prev_line_region is None: + log( 2, 'prev_line_region', prev_line_region, 'prev_line %r' % prev_line ) return not indent if self._is_paragraph_break(prev_line_region, prev_line): + log( 2, '_is_paragraph_break', self._is_paragraph_break(prev_line_region, prev_line) ) return not indent if new_paragraph_pattern.match(prev_line): + log( 2, 'new_paragraph_pattern', new_paragraph_pattern.match(prev_line), '%r' % prev_line ) return not indent if prev_line[0] == ' ' or prev_line[0] == '\t': - # prev_line might be a numbered list or a normal paragraph + log( 2, 'prev_line might be a numbered list or a normal paragraph: %r', prev_line ) return self._is_real_numbered_list(prev_line_region, prev_line, limit - 1, indent=True) if numbered_list_pattern.match(prev_line): + log( 2, 'numbered_list_pattern.match(prev_line)', numbered_list_pattern.match(prev_line).group(0), '%r' % prev_line ) return self._is_real_numbered_list(prev_line_region, prev_line, limit - 1) - return False # previous line appears to be a normal paragraph + log( 2, 'previous line appears to be a normal paragraph: %r', line ) + return False def _is_paragraph_start(self, line_region, line): # Certain patterns at the beginning of the line indicate this is the # beginning of a paragraph. if new_paragraph_pattern.match(line): - log(2, 'is not a new paragraph') + log( 2, 'is not a new paragraph %r', line ) return True if numbered_list_pattern.match(line): result = self._is_real_numbered_list(line_region, line) - log(2, 'is %sa paragraph continuation', 'not ' if result else '') + log( 2, 'is %sa paragraph continuation', 'not ' if result else '', '%r' % line ) return result - log(2, 'is not a paragraph') + log( 2, 'is not a paragraph %r', line ) return False def _is_paragraph_break(self, line_region, line, pure=False): @@ -363,6 +370,7 @@ def _is_paragraph_break(self, line_region, line, pure=False): if self._is_blank_line(line): return True scope_name = self.view.scope_name(line_region.begin()) log(2, 'scope_name=%r %r line=%r', scope_name, line_region, line) + if 'heading' in scope_name: log(2, "'heading' in scope_name") return True From e25aca6b4f2d1b260d17aef5d837ecf94050f01d Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Tue, 7 May 2019 09:09:25 -0300 Subject: [PATCH 148/160] Fixed nested numbered lists being broke by _is_real_numbered_list --- tests/wrap_tests/test.txt | 72 +++++++++++++++++++++++++++------------ wrap_plus.py | 2 +- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/tests/wrap_tests/test.txt b/tests/wrap_tests/test.txt index 1c46cdd..dfd532c 100644 --- a/tests/wrap_tests/test.txt +++ b/tests/wrap_tests/test.txt @@ -76,17 +76,57 @@ A. Lettered lists are similar to numbered lists. Don't hurry. Take your time ** Bullet item can have multiple characters. Topping muffin cupcake cotton candy soufflé cake pie. === +1. Execute os seguintes comandos: + 1. `pip3 uninstall khompdiag` + 1. `python3 setup.py develop` +--- +1. Execute os seguintes comandos: + 1. `pip3 uninstall khompdiag` + 1. `python3 setup.py develop` +=== Tests for embedded embedded numbers and lists. In this example we describe some fascinating events which first occurred in 2004. We're just mentioning 2004 in a sentence, so the rest of the paragraph should not be indented. +--- +Tests for embedded embedded numbers and lists. + +In this example we describe some fascinating events which first occurred in +2004. We're just mentioning 2004 in a sentence, so the rest of the paragraph +should not be indented. +=== +Tests for embedded embedded numbers and lists. + +In this example we describe some fascinating events which first occurred in +2004. We're just mentioning 2004 in a sentence, so the rest of the paragraph +should not be indented. +--- +Tests for embedded embedded numbers and lists. +In this example we describe some fascinating events which first occurred in +2004. We're just mentioning 2004 in a sentence, so the rest of the paragraph +should not be indented. +=== +1. Execute os seguintes comandos: + 1. `pip3 uninstall khompdiag` + 1. `python3 setup.py develop` +--- +1. Execute os seguintes comandos: + 1. `pip3 uninstall khompdiag` + 1. `python3 setup.py develop` +=== 5. A numbered list starts with a numbered list marker. 5#55#.#) the marker can be fairly complicated, but 5: markers must end with "." or ")" Test 6 6. markers cannot have any indent +--- +5. A numbered list starts with a numbered list marker. +5#55#.#) the marker can be fairly complicated, but 5: markers must end with + "." or ")" +Test 6 6. markers cannot have any indent +=== Test 7: to be recognized, a numbered list after a paragraph must start at 1. 7.1. for lists with subsections, the last section number is what matters 7.2. test 7 @@ -99,7 +139,17 @@ Test 8: otherwise, the numbered list is treated as a paragraph continuation Test 9: paragraph continuation after an indented paragraph 9. test 9 +--- +Test 7: to be recognized, a numbered list after a paragraph must start at 1. +7.1. for lists with subsections, the last section number is what matters +7.2. test 7 + +Test 8: otherwise, the numbered list is treated as a paragraph continuation +1.8. the last section number is what matters test 8, indent 2.8. test 8 a test +8 b + Test 9: paragraph continuation after an indented paragraph 9. test 9 +=== Test 10: continuation after test 10. an indented continuation 10. test 10 c @@ -111,28 +161,6 @@ Otherwise, #. Cupcake ipsum dolor sit amet marzipan faworki. Wafer I love croissant. Tart carrot cake pastry. #. Muffin ipsum dolor sit amet marzipan faworki. Wafer I love croissant. Tart carrot cake pastry. --- -Tests for embedded embedded numbers and lists. - -In this example we describe some fascinating events which first occurred in -2004. We're just mentioning 2004 in a sentence, so the rest of the paragraph -should not be indented. - -5. A numbered list starts with a numbered list marker. -5#55#.#) the marker can be fairly complicated, but 5: markers must end with - "." or ")" - -Test 6 6. markers cannot have any indent - -Test 7: to be recognized, a numbered list after a paragraph must start at 1. -7.1. for lists with subsections, the last section number is what matters -7.2. test 7 - -Test 8: otherwise, the numbered list is treated as a paragraph continuation -1.8. the last section number is what matters test 8, indent 2.8. test 8 a test -8 b - - Test 9: paragraph continuation after an indented paragraph 9. test 9 - Test 10: continuation after test 10. an indented continuation 10. test 10 c 11. Wrapped lines must be indented; any amount of indentation is recognized. diff --git a/wrap_plus.py b/wrap_plus.py index 543f416..d125bee 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -267,7 +267,7 @@ def CONCAT(*args): phrase_separator_characters = set( word_separator_characters ) - set( list_separator_characters ) # This doesn't always work, but seems decent. -numbered_list = r'(?:(?:([0-9#]+)[.)])+[\t ])' +numbered_list = r'[\t ]*(?:(?:([0-9#]+)[.)])+[\t ])' numbered_list_pattern = re.compile(numbered_list) lettered_list = r'(?:[a-zA-Z][.)][\t ])' bullet_list = r'(?:[*+#-]+[\t ])' From 8b6c38763feffe932ac10c425f747ca33245f64a Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 May 2019 00:42:10 -0300 Subject: [PATCH 149/160] Recreated the paragraphs types for '\[\{\(' Related: 7af3e3b9ef02c9256f237c37dbbdf20a45ec6afd Created new paragraphs types '\[\{\(' for the form: \preambulo { \chooselang {Tese submetida ao Federal de \showfont} {Tese submetida ao asdfffffffffffffasd fdaf adsf df asfd asfd asdf sdf asdf adaf df ads fasd f Federal de \showfont} } --- wrap_plus.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index d125bee..8123d15 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -276,7 +276,8 @@ def CONCAT(*args): rest_directive = r'(?:\.\.)' field_start = r'(?:[:@])' # rest, javadoc, jsdoc, etc. -new_paragraph_pattern_string = r'^[\t ]*' + OR(lettered_list, bullet_list, field_start, r'\{') +start_line_block = r'(?:\{|\})' +new_paragraph_pattern_string = r'^[\t ]*' + OR(lettered_list, bullet_list, field_start, start_line_block) log(4, "pattern", new_paragraph_pattern_string) new_paragraph_pattern = re.compile(new_paragraph_pattern_string) @@ -492,7 +493,10 @@ def _find_paragraphs(self, sublime_text_region): if is_empty: log(2, 'empty sel on paragraph break %r', current_line,) return [] - current_line_region, current_line = view.next_line(current_line_region) + new_current_line_region, new_current_line = view.next_line(current_line_region) + log( 2, 'current_line_region', new_current_line_region, 'current_line', new_current_line ) + if new_current_line is None: break + current_line_region, current_line = new_current_line_region, new_current_line paragraph_start_pt = current_line_region.begin() paragraph_end_pt = current_line_region.end() @@ -1357,7 +1361,7 @@ def is_word_separator_alpha(self, index, text, checklisk): backboundary = ( text[index-separator_length] in whitespace_character and text[index-separator_length-1] not in word_separator_characters - and not not spaces_pattern.match( text[index+1] ) + and index + 1 < len( text ) and not not spaces_pattern.match( text[index+1] ) ) is_word_backboundary = backboundary and character.isalpha() or not backboundary and not character.isalpha() log( 4, separator, is_word_backboundary, backboundary ) From a33132cee74d7fb60227cf551b31557fbc2573d6 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 8 May 2019 09:30:11 -0300 Subject: [PATCH 150/160] Fixed new line being printed when debug mode is disabled. --- wrap_plus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index 8123d15..7a21e1e 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1128,7 +1128,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li new_lines.append( fixed_wrapped_lines ) - log.clean("") + log.clean(4, "") log( 4, "new_lines %s", new_lines ) return new_lines From a0066699850f9732d7a0a9a6a3f37c937863b602 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 5 Jun 2019 02:18:14 -0300 Subject: [PATCH 151/160] Added support to latex math environment $$var$$ --- wrap_plus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrap_plus.py b/wrap_plus.py index 7a21e1e..a00f228 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -256,7 +256,7 @@ def CONCAT(*args): first_group = lambda x: r"(?:^[\t \{\}\n]%s(?:````?.*)?)" % x -blank_line_pattern = re.compile( r'({}$|{}(?:[%/].*)?$|(?:.*"""\\?$))'.format( first_group('*'), first_group('+') ) ) +blank_line_pattern = re.compile( r'({}$|{}(?:[%/].*)?$|(?:.*"""\\?$)|.*\$\$.+)'.format( first_group('*'), first_group('+') ) ) # print('pattern', blank_line_pattern.pattern) next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) From 01a350bbcc443208080685ce9c66321a533d20ff Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 5 Jun 2019 03:06:27 -0300 Subject: [PATCH 152/160] Added custom parameters to is_there_line_over_the_wrap_limit() --- wrap_plus.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index a00f228..98724a1 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1055,16 +1055,19 @@ def is_there_line_over_the_wrap_limit(self, new_lines): return False - def is_there_lonely_word_line(self, new_lines): + def is_there_lonely_word_line(self, new_lines, maximumwidth=None, limitpercent=None): """ Check whether there is some line with a single big word only. If so, it means, we must to stop wrapping with traditional line balancing algorithm. """ + limitpercent = limitpercent if limitpercent else 0.8 + maximumwidth = maximumwidth if maximumwidth else self._width + for new_line in new_lines: longest = -1 line_length = len( new_line ) - line_percent_size = math.ceil( line_length / self._width ) + line_percent_size = math.ceil( line_length / maximumwidth ) for match in not_spaces_pattern.finditer( new_line ): start, end = match.span() @@ -1073,8 +1076,8 @@ def is_there_lonely_word_line(self, new_lines): if length > longest: longest = length - new_width = 0.95 if longest > self._width else line_percent_size - line_limit = self._width * 0.8 + new_width = 0.95 if longest > maximumwidth else line_percent_size + line_limit = maximumwidth * limitpercent log( 4, 'line_percent_size', line_percent_size, 'line_length', line_length, 'longest', longest, 'new_width', new_width, 'line_limit', line_limit ) From 20dc023a9400749bbd936074a0744e2db1dd2020 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 5 Jun 2019 03:07:42 -0300 Subject: [PATCH 153/160] Fixed balanced line wrapping breaking early lines with big words --- tests/test_wrap.py | 3 ++- tests/wrap_tests/semantic_test.tex | 11 +++++++++-- wrap_plus.py | 26 +++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/tests/test_wrap.py b/tests/test_wrap.py index 357986d..b827626 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -199,7 +199,8 @@ def load_tests(loader, standard_tests, pattern): suite = unittest.TestSuite() # See _NAME above to get the test class name pattern # suite.addTest( integration_test_txt_15_tests( 'test_thing' ) ) - suite.addTest( integration_semantic_test_tex_02_tests( 'test_thing' ) ) + # suite.addTest( integration_semantic_test_tex_02_tests( 'test_thing' ) ) + suite.addTest( integration_semantic_test_tex_03_tests( 'test_thing' ) ) return suite # Comment this to run individual Unit Tests diff --git a/tests/wrap_tests/semantic_test.tex b/tests/wrap_tests/semantic_test.tex index 21fc300..0c88b06 100644 --- a/tests/wrap_tests/semantic_test.tex +++ b/tests/wrap_tests/semantic_test.tex @@ -33,10 +33,17 @@ Já que para compartilhar código e trabalhar em times de forma eficiente, é essential utilizar\hyp{}se um sistema de versionamento\footnote{\url{http://www.codeservedcold.com/version-control-importance/}} que permita -o gerente de projetos e os próprios programadores +o gerente de projetos e os próprios --- Já que para compartilhar código e trabalhar em times de forma eficiente, é essential utilizar\hyp{}se um sistema de versionamento\footnote{\url{http://www.codeservedcold.com/version-control-importance/}} que -permita o gerente de projetos e os próprios programadores +permita o gerente de projetos e os próprios +=== + A figura \ref{fig:pictures/LinguagensDeterministicas.png} não é + inteiramente um Diagrama de Venn \cite{generalizedVennDiagrams}, mas sim. +--- + A figura \ref{fig:pictures/LinguagensDeterministicas.png} não é + inteiramente um Diagrama de Venn \cite{generalizedVennDiagrams}, + mas sim. diff --git a/wrap_plus.py b/wrap_plus.py index 98724a1..6e921f5 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1086,6 +1086,30 @@ def is_there_lonely_word_line(self, new_lines, maximumwidth=None, limitpercent=N return False + def is_there_big_word_on_line(self, line, new_width): + """ + Check whether there is some big word on the line. + + If so, returns the `new_width` properly fixed for wrapping.fill() + """ + longest = -1 + wordlimit = new_width * 0.5 + + for match in not_spaces_pattern.finditer( line ): + start, end = match.span() + length = end - start + + if length > longest: + longest = length + + log( 4, 'longest', longest, 'wordlimit', wordlimit, 'new_width', new_width ) + if longest > wordlimit: + new_width = new_width + wordlimit * 0.1 + log( 4, 'new_width', new_width ) + return new_width + + return new_width + def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_line_increment_percent=1): """ (input) text_lines: [' This is my very long line which will wrap near its end,\n'] @@ -1113,7 +1137,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li log( 4, "maximum_line_width %d new_width %d (%f)", maximum_line_width, new_width, middle_of_the_line_increment_percent ) log( 4, "line %r", line ) - wrapper.width = new_width + wrapper.width = self.is_there_big_word_on_line( line, new_width ) wrapped_line = wrapper.fill( line ) log( 4, "wrapped_line %r", wrapped_line ) From 57c5549680066c3635f9fa7b7058eeab207f9f53 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Wed, 5 Jun 2019 03:13:45 -0300 Subject: [PATCH 154/160] Added new debug messages to is_there_lonely_word_line() --- wrap_plus.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 6e921f5..48a010a 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -1076,14 +1076,17 @@ def is_there_lonely_word_line(self, new_lines, maximumwidth=None, limitpercent=N if length > longest: longest = length - new_width = 0.95 if longest > maximumwidth else line_percent_size + percentwidth = 0.95 if longest > maximumwidth else line_percent_size line_limit = maximumwidth * limitpercent log( 4, 'line_percent_size', line_percent_size, 'line_length', line_length, - 'longest', longest, 'new_width', new_width, 'line_limit', line_limit ) + 'longest', longest, 'percentwidth', percentwidth, 'line_limit', line_limit, + 'new_line', new_line ) if longest > line_limit: - return new_width + log( 4, 'TRUE, percentwidth', percentwidth ) + return percentwidth + log( 4, 'FALSE' ) return False def is_there_big_word_on_line(self, line, new_width): @@ -1116,6 +1119,7 @@ def _split_lines(self, wrapper, text_lines, maximum_line_width, middle_of_the_li (output) new_lines: [[' This is my very long line\n', ' which will wrap near its\n', ' end,\n']] """ new_lines = [] + log( 4, 'text_lines', text_lines ) initial_indent = wrapper.initial_indent subsequent_indent = wrapper.subsequent_indent From 22b515d6fe8460ecfd400d8022cd5e4c67b1ef06 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 15 Jun 2019 12:18:34 -0300 Subject: [PATCH 155/160] Created a new Unit Test for semantic_80_test.tex which is falling currently. --- tests/test_wrap.py | 35 ++++++++++++++++++++++++--- tests/wrap_tests/semantic_80_test.tex | 9 +++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 tests/wrap_tests/semantic_80_test.tex diff --git a/tests/test_wrap.py b/tests/test_wrap.py index b827626..bb4a0be 100644 --- a/tests/test_wrap.py +++ b/tests/test_wrap.py @@ -45,6 +45,27 @@ 'WrapPlus.skip_range': False, # Workaround for a bug. } +SEMANTIC_SETTINGS_80 = { + 'word_wrap': False, + 'wrap_width': 0, + 'rulers': [], + 'tab_size': 4, + 'translate_tabs_to_spaces': False, + 'WrapPlus.break_long_words': False, + 'WrapPlus.break_on_hyphens': False, + 'WrapPlus.after_wrap': 'cursor_below', + 'WrapPlus.semantic_line_wrap': True, + "WrapPlus.semantic_balance_characters_between_line_wraps": True, + "WrapPlus.semantic_minimum_line_size_percent": 0.0, + "WrapPlus.semantic_wrap_extension_percent": 1.2, + "WrapPlus.semantic_maximum_items_in_comma_separated_list": 1, + "WrapPlus.semantic_maximum_words_in_comma_separated_list": 3, + "WrapPlus.semantic_disable_line_wrapping_by_maximum_width": False, + 'WrapPlus.include_line_endings': 'auto', + 'WrapPlus.wrap_width': 80, + 'WrapPlus.skip_range': False, # Workaround for a bug. +} + has_failures = [] def make_wrap_tests(): @@ -157,7 +178,15 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): bad_keys = set(settings.keys()) - set(DEFAULT_SETTINGS.keys()) self.assertEqual(bad_keys, set()) - settings_type = SEMANTIC_SETTINGS.items() if filename.startswith('semantic') else DEFAULT_SETTINGS.items() + if filename.startswith('semantic_80'): + settings_type = SEMANTIC_SETTINGS_80.items() + + elif filename.startswith('semantic'): + settings_type = SEMANTIC_SETTINGS.items() + + else: + settings_type = DEFAULT_SETTINGS.items() + for setting_name, value in settings_type: value = settings.get(setting_name, value) if value == UNSET: @@ -176,7 +205,7 @@ def _wrap_with_scratch(self, filename, contents, expected, syntax, settings, f): test_name = [] for character in filename: - if character.isalpha(): + if character.isalnum(): test_name.append(character.lower()) else: test_name.append('_') @@ -200,7 +229,7 @@ def load_tests(loader, standard_tests, pattern): # See _NAME above to get the test class name pattern # suite.addTest( integration_test_txt_15_tests( 'test_thing' ) ) # suite.addTest( integration_semantic_test_tex_02_tests( 'test_thing' ) ) - suite.addTest( integration_semantic_test_tex_03_tests( 'test_thing' ) ) + suite.addTest( integration_semantic_80_test_tex_00_tests( 'test_thing' ) ) return suite # Comment this to run individual Unit Tests diff --git a/tests/wrap_tests/semantic_80_test.tex b/tests/wrap_tests/semantic_80_test.tex new file mode 100644 index 0000000..edd5180 --- /dev/null +++ b/tests/wrap_tests/semantic_80_test.tex @@ -0,0 +1,9 @@ +Packages/LaTeX/LaTeX.sublime-syntax +=== + eles precisam de computadores que suportem a execução simultânea dos + diversos ramos de computação tal como Computadores Quânticos podem + fazer em alguns casos com execução probabilística. +--- + eles precisam de computadores que suportem a execução simultânea dos + diversos ramos de computação tal como Computadores Quânticos podem + fazer em alguns casos com execução probabilística. From 9d333b71a8f5e591d00c2ba96b322e97261b0e73 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 22 Jun 2019 15:10:23 -0300 Subject: [PATCH 156/160] Fixed escaped colons not being handled by fields --- wrap_plus.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wrap_plus.py b/wrap_plus.py index 48a010a..9971d24 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -283,8 +283,7 @@ def CONCAT(*args): new_paragraph_pattern = re.compile(new_paragraph_pattern_string) space_prefix_pattern = re.compile(r'^[ \t]*') -# XXX: Does not handle escaped colons in field name. -fields = OR(r':[^:]+:', '@[a-zA-Z]+ ') +fields = OR(r'(? Date: Sat, 22 Jun 2019 15:11:26 -0300 Subject: [PATCH 157/160] Created new setting from hard coded values on source code "WrapPlus.start_line_block": "(?:\\{|\\})", "WrapPlus.whitespace_character": [" ", "\\t"], "WrapPlus.alpha_separator_characters": ["e", "and", "or", "ou"], "WrapPlus.list_separator_characters": [ ",", ";"], "WrapPlus.word_separator_characters": [ ".", "?", "!", ":"], --- Preferences.sublime-settings | 8 +++++++- wrap_plus.py | 36 ++++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/Preferences.sublime-settings b/Preferences.sublime-settings index ca859f7..6a9f6b0 100644 --- a/Preferences.sublime-settings +++ b/Preferences.sublime-settings @@ -22,6 +22,12 @@ // Set the wrap column, overriding Sublime's "wrap_width" if not 0. // "WrapPlus.wrap_width": 78 + "WrapPlus.start_line_block": "(?:\\{|\\})", + "WrapPlus.whitespace_character": [" ", "\\t"], + "WrapPlus.alpha_separator_characters": ["e", "and", "or", "ou"], + "WrapPlus.list_separator_characters": [ ",", ";"], + "WrapPlus.word_separator_characters": [ ".", "?", "!", ":"], + // If true, the semantic linewrap also know as semantic linefeed will be used. // See the following address for more descriptions: // http://rhodesmill.org/brandon/2012/one-sentence-per-line/ @@ -39,7 +45,7 @@ // will wrap near its end, // // This is valid only when the `WrapPlus.semantic_line_wrap` above is enabled. - "WrapPlus.semantic_balance_characters_between_line_wraps": true, + "WrapPlus.semantic_balance_characters_between_line_wraps": false, // The minimum of the percentage of the current maximum line width a line can // have. For example, if you `wrap_width` is set to 100, and you set this to `0.2`, diff --git a/wrap_plus.py b/wrap_plus.py index 9971d24..bb1d230 100644 --- a/wrap_plus.py +++ b/wrap_plus.py @@ -257,14 +257,9 @@ def CONCAT(*args): first_group = lambda x: r"(?:^[\t \{\}\n]%s(?:````?.*)?)" % x blank_line_pattern = re.compile( r'({}$|{}(?:[%/].*)?$|(?:.*"""\\?$)|.*\$\$.+)'.format( first_group('*'), first_group('+') ) ) -# print('pattern', blank_line_pattern.pattern) - next_word_pattern = re.compile(r'\s+[^ ]+', re.MULTILINE) -whitespace_character = (" ", "\t") -alpha_separator_characters = ('e', 'and') -list_separator_characters = ( ",", ";") -word_separator_characters = ( ".", "?", "!", ":" ) + list_separator_characters -phrase_separator_characters = set( word_separator_characters ) - set( list_separator_characters ) +space_prefix_pattern = re.compile(r'^[ \t]*') +log( 4, "pattern blank_line_pattern", blank_line_pattern.pattern ) # This doesn't always work, but seems decent. numbered_list = r'[\t ]*(?:(?:([0-9#]+)[.)])+[\t ])' @@ -276,13 +271,6 @@ def CONCAT(*args): rest_directive = r'(?:\.\.)' field_start = r'(?:[:@])' # rest, javadoc, jsdoc, etc. -start_line_block = r'(?:\{|\})' -new_paragraph_pattern_string = r'^[\t ]*' + OR(lettered_list, bullet_list, field_start, start_line_block) -log(4, "pattern", new_paragraph_pattern_string) - -new_paragraph_pattern = re.compile(new_paragraph_pattern_string) -space_prefix_pattern = re.compile(r'^[ \t]*') - fields = OR(r'(? Date: Sat, 6 Jul 2019 20:39:18 -0300 Subject: [PATCH 158/160] Fixed Preferences.sublime-settings list spacing formatting --- Preferences.sublime-settings | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Preferences.sublime-settings b/Preferences.sublime-settings index 6a9f6b0..2b461eb 100644 --- a/Preferences.sublime-settings +++ b/Preferences.sublime-settings @@ -23,10 +23,10 @@ // "WrapPlus.wrap_width": 78 "WrapPlus.start_line_block": "(?:\\{|\\})", - "WrapPlus.whitespace_character": [" ", "\\t"], - "WrapPlus.alpha_separator_characters": ["e", "and", "or", "ou"], - "WrapPlus.list_separator_characters": [ ",", ";"], - "WrapPlus.word_separator_characters": [ ".", "?", "!", ":"], + "WrapPlus.whitespace_character": [ " ", "\\t" ], + "WrapPlus.alpha_separator_characters": [ "e", "and", "or", "ou" ], + "WrapPlus.list_separator_characters": [ ",", ";" ], + "WrapPlus.word_separator_characters": [ ".", "?", "!", ":" ], // If true, the semantic linewrap also know as semantic linefeed will be used. // See the following address for more descriptions: From 842252b3faf8c3f0295a90d644c22a82acdcfe15 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sat, 28 Sep 2019 22:40:27 -0300 Subject: [PATCH 159/160] Updated README.md installation instructions --- README.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 806bd25..b8f8f44 100644 --- a/README.md +++ b/README.md @@ -10,29 +10,28 @@ Enhanced "wrap lines" command for Sublime Text 2 or 3. This is for the *manual* hard line wrap command (AltQ in Windows and Linux, CommandAltQ in OS X). It does not affect the automatic soft line wrapping. -## Downloading -The best way to download and install Sublime Wrap Plus is to use the [Package Control](https://packagecontrol.io) plugin. If you do not already have it installed, it's really the best way to manage your packages. -For users new to the package manager: +## Installation -* Go to https://packagecontrol.io/installation and install Package Control. -* Restart Sublime Text. +### By Package Control -Install Sublime Wrap Plus: +1. Download & Install `Sublime Text 3` (https://www.sublimetext.com/3) +1. Go to the menu `Tools -> Install Package Control`, then, + wait few seconds until the `Package Control` installation finishes +1. Go to the menu `Preferences -> Package Control` +1. Type `Package Control Add Channel` on the opened quick panel and press Enter +1. Then, input the following address and press Enter + ``` + https://raw.githubusercontent.com/evandrocoan/StudioChannel/master/channel.json + ``` +1. Now, go again to the menu `Preferences -> Package Control` +1. This time type `Package Control Install Package` on the opened quick panel and press Enter +1. Then, search for `WrapPlus` and press Enter -* Bring up the Command Palette (CommandShiftP on OS X, CtrlShiftP on Linux/Windows). -* Select ***`Package Control: Install Package`*** and wait while Package Control fetches the latest package list. -* Select Wrap Plus when the list appears. +See also: +1. [ITE - Integrated Toolset Environment](https://github.com/evandrocoan/ITE) +1. [Package control docs](https://packagecontrol.io/docs/usage) for details. -Package Control will handle automatically updating your packages. - -Alternatively, you can fetch from Github: - -``` -git clone git://github.com/ehuss/Sublime-Wrap-Plus.git -``` - -and place it in your Packages directory, which can be found by selecting **`Preferences → Browse Packages...`**. ## Configuring No need to configure anything. By default it uses the default keystroke for wrap lines: From 45f4927a39c2253e9c2686241ad1fdf6435a8394 Mon Sep 17 00:00:00 2001 From: evandrocoan Date: Sun, 29 Sep 2019 16:07:47 -0300 Subject: [PATCH 160/160] Fixed README.md installation instructions --- README.md | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b8f8f44..8c0fc16 100644 --- a/README.md +++ b/README.md @@ -15,18 +15,35 @@ Enhanced "wrap lines" command for Sublime Text 2 or 3. This is for the *manual* ### By Package Control -1. Download & Install `Sublime Text 3` (https://www.sublimetext.com/3) -1. Go to the menu `Tools -> Install Package Control`, then, - wait few seconds until the `Package Control` installation finishes -1. Go to the menu `Preferences -> Package Control` -1. Type `Package Control Add Channel` on the opened quick panel and press Enter -1. Then, input the following address and press Enter +1. Download & Install **`Sublime Text 3`** (https://www.sublimetext.com/3) +1. Go to the menu **`Tools -> Install Package Control`**, then, + wait few seconds until the installation finishes up +1. Go to the menu **`Tools -> Command Palette... + (Ctrl+Shift+P)`** +1. Type **`Preferences: + Package Control Settings – User`** on the opened quick panel and press Enter +1. Then, + add the following setting to your **`Package Control.sublime-settings`** file, if it is not already there + ```js + [ + ... + "channels": + [ + "https://raw.githubusercontent.com/evandrocoan/StudioChannel/master/channel.json", + "https://packagecontrol.io/channel_v3.json", + ], + ... + ] ``` - https://raw.githubusercontent.com/evandrocoan/StudioChannel/master/channel.json - ``` -1. Now, go again to the menu `Preferences -> Package Control` -1. This time type `Package Control Install Package` on the opened quick panel and press Enter -1. Then, search for `WrapPlus` and press Enter + * Note, + the **`https://raw...`** line must to be added before the **`https://packagecontrol...`**, + otherwise you will not install this forked version of the package, + but the original available on the Package Control default channel **`https://packagecontrol...`** +1. Now, + go to the menu **`Preferences -> Package Control`** +1. Type **`Install Package`** on the opened quick panel and press Enter +1. Then, +search for `WrapPlus` and press Enter See also: 1. [ITE - Integrated Toolset Environment](https://github.com/evandrocoan/ITE)