-
Notifications
You must be signed in to change notification settings - Fork 592
[reST] refactor #4212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[reST] refactor #4212
Conversation
b40f0f7
to
8817eaf
Compare
72e437b
to
ae329e0
Compare
Thanks a lot for taking care of this.
Example file having lots of these: https://raw.githubusercontent.com/giampaolo/psutil/refs/heads/master/HISTORY.rst. |
843a5bc
to
0607aca
Compare
ebfb8c4
to
c34db53
Compare
6bfcc32
to
5d0438e
Compare
Hello, @jrappen ! Good morning! And thank you for the invitation in sublimetext-io/docs.sublimetext.io#131. My name is Vic. I have been implementing these import sublime
import sublime_plugin
class VicsRstEncapsulateFieldCommand(sublime_plugin.TextCommand):
"""
If (conditions applied in keymap):
- we are in a reStructuredText source file, and
- all selections have some text selected
then wrap the selected text like this:
:selected text:
"""
def run(self, edit):
sel_list = self.view.sel()
# Replace each selection with edited string.
for rgn in reversed(sel_list):
selected_text = self.view.substr(rgn)
new_text = ':' + selected_text + ':'
self.view.replace(edit, rgn, new_text)
# De-select each selection, leaving cursor on right edge of its
# previous selection. This avoids the danger of a stray keystroke
# wiping out the new text.
for i, rgn in enumerate(sel_list):
del sel_list[i]
sel_list.add(sublime.Region(rgn.end()))
class VicsRstEncapsulateLiteralCommand(sublime_plugin.TextCommand):
"""
If (conditions applied in keymap):
- we are in a reStructuredText source file, and
- all selections have some text selected
then wrap the selected text like this:
``selected text``
"""
def run(self, edit):
sel_list = self.view.sel()
# Replace each selection with edited string.
for rgn in reversed(sel_list):
selected_text = self.view.substr(rgn)
new_text = '``' + selected_text + '``'
self.view.replace(edit, rgn, new_text)
# De-select each selection, leaving cursor on right edge of its
# previous selection. This avoids the danger of a stray keystroke
# wiping out the new text.
for i, rgn in enumerate(sel_list):
del sel_list[i]
sel_list.add(sublime.Region(rgn.end()))
class VicsRstEncapsulateInterpretedTextRoleCommand(sublime_plugin.TextCommand):
"""
If (conditions applied in keymap):
- we are in a reStructuredText source file, and
- all selections have some text selected
then wrap the selected text like this:
:role_name:`selected text`
"""
def run(self, edit, role_name):
sel_list = self.view.sel()
# Replace each selection with edited string.
for rgn in reversed(sel_list):
selected_text = self.view.substr(rgn)
new_text = f':{role_name}:`{selected_text}`'
self.view.replace(edit, rgn, new_text)
# De-select each selection, leaving cursor on right edge of its
# previous selection. This avoids the danger of a stray keystroke
# wiping out the new text.
for i, rgn in enumerate(sel_list):
del sel_list[i]
sel_list.add(sublime.Region(rgn.end())) // --------------------------------------------------------------------
// reStructuredText Tools
// --------------------------------------------------------------------
{
"keys": ["ctrl+alt+f"],
"command": "vics_rst_encapsulate_field",
"context":
[
{ "key": "selector", "operand": "text.restructuredtext"},
{ "key": "selection_empty", "operand": false, "match_all": true },
]
},
{
"keys": ["ctrl+alt+l"], // Lower-case 'L'
"command": "vics_rst_encapsulate_literal",
"context":
[
{ "key": "selector", "operand": "text.restructuredtext"},
{ "key": "selection_empty", "operand": false, "match_all": true },
]
},
{
"keys": ["ctrl+alt+t"],
"command": "vics_rst_encapsulate_interpreted_text_role",
"args": {
"role_name": "term"
},
"context":
[
{ "key": "selector", "operand": "text.restructuredtext"},
{ "key": "selection_empty", "operand": false, "match_all": true },
]
}, Use Case for
|
@vwheeler63 Thanks Vic! I do have a question, though. When replacing multiple selections, why go forward through the list instead of backwards? You say this is well tested, I ... doubt it?! Because if you go forward you'd have to re-adjust the current selection and all following ones every step, if you go backward you can just replace. Your way doesn't make sense in my mind, without testing. I'm fairly certain, I've seen other plugins use the reverse order for the same reason, too. |
That's a great question! Interestingly, I initially made it backwards using (reversed()) but after closely examining the
There are definitely some things (when additional editing is being done) that require keeping track of the displaced text. I am developing another complex packages that does so in several places. I am aware that some kind of |
@jrappen with regard to forward-loops working: Case 1:If you iterate through a list of regions that are anything other than a Example: pat = pc_setting.placeholder_line_regex.pattern
flags = sublime.FindFlags.NONE # NONE = regex
fmt = r'\1,\2,\3'
extractions = []
placeholder_rgns = cmd.view.find_all(pat, flags, fmt, extractions)
# Here `placeholder_rgns` is NOT a `sublime.Selection` object!
adjust = 0
for i, rgn in enumerate(placeholder_rgns):
adjusted_rgn= sublime.Region(rgn.a - adjust, rgn.b - adjust)
# Here, any self.view.replace() operations have to keep track of the
# shift in the buffer contents going forward. This is because
# `placeholder_rgns` IS NOT a `sublime.Selections` object.
...compute `new_text` here...
self.view.replace(edit, adjusted_rgn, new_text)
adjust += (adjusted_rgn.size() - len(new_text)) Case 2:However, when you are iterating on an actual The same thing happens if you iterate on a sel_list = self.view.sel() # Unlike the above, this is a `sublime.Selection` object.
# Replace each selection with edited string.
for rgn in sel_list:
selected_text = self.view.substr(rgn)
new_text = '``' + selected_text + '``'
self.view.replace(edit, rgn, new_text) works as intended because of the You can see how the "current version" of each indexed selection is returned for each iteration of the def __iter__(self) -> Iterator[Region]:
"""
Iterate through all the regions in the selection.
.. since:: 4023 3.8
"""
i = 0
n = len(self)
while i < n:
yield sublime_api.view_selection_get(self.view_id, i)
i += 1 It is better to have "reversed()" in the iterator. |
@vwheeler63 I cleaned up our discussion a bit, as it makes it easier for me to read while going through TODOs here. I hope you don't mind. |
@vwheeler63 Do you know of a page that lists Sphinx's additions to reST? |
Not at all.
It's not in one place, but what the Sphinx doc guys did is they let the Docutils documentation handle the basics, and the Sphinx docs (e.g. Directives, Interpreted Text Roles, etc.) only documents things that Sphinx added (or significantly changed), which IMO, VERY much helps the reader understand what Sphinx contributed to the |
9afd1f3
to
3f8b966
Compare
Note
This PR is mainly meant to make future work easier, not necessarily
fix stuff now. If you have suggestions for stuff that should be fixed
now, leave a comment below.
current TODOs
Additions:
footnotes, citations)
jsonc, html, python, toml, yaml), compare [reStructuredText] Code-blocks are not handled #3158
targets
interpreted text roles
lines
Fixes:
[RestructuredText] single quotes break link targets #1204
Changes:
section headings and their punctuation
scope naming guide
punctuation.definition.end
rules for inline itemsbefore
invalid.illegal.newline
compare [reST] Internal link labels should allow more character types #793
auto_complete_selector
defaultdirective names
References:
syntax don't get lost
Thanks to these contributors: