UI: Add a custom text editor preference #108299
No reviewers
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#108299
Loading…
Reference in New Issue
No description provided.
Delete Branch "guishe:edit-source"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Add a user preference to set up a custom text editor for editing text
files with the "Edit Source" action in the UI context menu.
here a video showing the added user preference
UI: Add a custom Text Editorto WIP: UI: Add a custom Text EditorPerhaps a solution similar to the Animation Player would work best.
An enum with options:
Internal
Visual Studio Code
Custom
Having the ability to open an external text editor at a location is a nice addition.
Having
BLI_windows_open_text_file_execute
is unnecessarily low level (and MS-Windows only). In general having C/C++ handle external processes isn't very convenient. Properly reporting if the command isn't found or fails for example - becomes overly involved.Having this hard-coded to VS-Code formatted arguments is also not acceptable, as Pablo suggests, this can use presets with the option of a custom editor.
Instead of launching the process via ShellExecuteExW, an operator can be added e.g.
TEXT_OT_jump_to_file_at_point
which can implemented in Python and either call into Blender's text editor (as happens already), or opens an external process - depending on a user-preference.Requesting this be implemented as an operator in Python to avoid platform spesific handling of external processes.
3a13854695
to530607c8b3
530607c8b3
tof4581cfc9a
f4581cfc9a
todeb923f0b0
I would like to know if you have any suggestions for other text editors to add as presets
should these preferences be hidden if
context.preferences.view.show_developer_ui == false
?No I think it should always be visible. And we could add the operator to the Text menu in the Text Editor header to "Edit Externally", just like the image editor: https://docs.blender.org/manual/en/latest/editors/image/editing.html#edit-externally
deb923f0b0
to662aee7838
Added!
662aee7838
toa358c3e45c
a358c3e45c
to4211c1a3dd
4211c1a3dd
toeb96b6e231
WIP: UI: Add a custom Text Editorto UI: Add a custom Text Editoreb96b6e231
tof91ace53f5
@ -433,6 +441,32 @@ class TEXT_MT_context_menu(Menu):
layout.operator("text.autocomplete")
class TEXT_OT_jump_to_file_at_line(Operator):
Should be added to
scripts/startup/bl_operators/text.py
@ -1751,0 +1754,4 @@
RNA_int_set(&op_props, "line", line);
int result = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props, NULL);
if (result == OPERATOR_FINISHED) {
Should be
result & OPERATOR_FINISHED
@ -250,0 +252,4 @@
row = layout.row()
op = row.operator("text.jump_to_file_at_line", text="Edit Externally")
op.filepath = text.filepath
There is no need to set these variables, the jump_to_file_at_line operator can initialize them from the context if they are not already set.
e.g.
if self.properties.is_property_set("filepath")
efe759a3a5
to8fa4ef1e84
Looking into this I think it would be better if some of the details of this patch were changed.
Mainly because there are so many editors, they come and go, having a comprehensive list with invocation commands on all platforms over time is likely to get messy, if we had maintained such a list over the last decade it would include editors that are no longer in common use, but as they would have a "slot" in blender's UI & preferences, removing them could always annoy some developers.
The changes I'd like to see to this patch aren't so large but involve some different areas of the API.
text_editor
field, when it's a blank string, use blender's internal text editor.text_editor_preset
.{file}
{line}
{column}
.scripts/presets/framerate
.This way the preset just sets the command to open the editor, removing a preset wont prevent someone continuing to use their editor.
Requesting removal of hard coded presets in favor of only an editor command, with presets that fill in it's value.
Instead of a generic invocation, can i set a string field
text_editor_args
where the user can specify the format of arguments of the specific editor, if not specified use the generic invocationHere the changes. One problem I need to fix is that when saving a custom setting, then reopening Blender, the inputs won't be visible until the user selects custom again
@ -0,0 +28,4 @@
args = [text_editor]
if not text_editor_args:
text_editor_args = "{file} {line} {column}"
Prefer not to do this, it's unlikely to work for most editors and will just leave the user with a confusing error message, instead, report an error that no argument preferences were set and return.
@ -0,0 +30,4 @@
if not text_editor_args:
text_editor_args = "{file} {line} {column}"
text_editor_args = text_editor_args.format(file=self.filepath, line=self.line, column=self.column)
Even though
str.format(..)
seems useful, I think it's best not to use it because it potentially exposes a lot of complexity for a situation where we only want to substitute a few known identifiers. Format strings could be malformed which should be reported to the user (if formatting fails), and there are even security implications although in practice anyone with control over the preferences can already change automatic execution options. Nevertheless, I'd rather avoid and instead replace known identifiers, where each element is searched and replaced.Python's standard library already has a solution for this which I think fits this use case well: https://docs.python.org/3/library/string.html#string.Template.substitute
@ -0,0 +31,4 @@
text_editor_args = "{file} {line} {column}"
text_editor_args = text_editor_args.format(file=self.filepath, line=self.line, column=self.column)
args.extend(text_editor_args.split(" "))
Use
shlex.split
to account for quoted arguments.Also, safest to split before substituting in arguments so spaces or quotes in filenames don't cause problems.
@ -0,0 +40,4 @@
return {'CANCELLED'}
return {'FINISHED'}
except:
return {'CANCELLED'}
The error output should be included in a report if the process fails to start, otherwise it's difficult to know what went wrong.
@ -1405,0 +1425,4 @@
show_input = preset_label == "Custom"
if show_input:
text_editor_label = tip_("Custom (%s)") % text_editor
Prefer term "External" to custom (as all editors are effectively custom now).
@ -728,2 +728,4 @@
char image_editor[1024];
/** 1024 = FILE_MAX. */
char text_editor[1024];
char text_editor_args[1024];
Worth noting that
text_editor_args
is not actually a file-path as hinted by theFILE_MAX
length, can be much smaller as the value is expanded - although the value is arbitrary, suggest 256.@ -6507,0 +6511,4 @@
prop = RNA_def_property(srna, "text_editor_args", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "text_editor_args");
RNA_def_property_ui_text(prop, "Text Editor Args", "text_editor_args");
Supported expansions should be noted here (file/line/column).
@ -0,0 +1,5 @@
import bpy
import platform
bpy.context.preferences.filepaths.text_editor = "code.cmd" if platform.system() == 'Windows' else "code"
In this case I think it makes most sense to use a
match
statement, this allows for other platforms to be added more easily as well as the default case to be clearer.@ -0,0 +1,5 @@
import bpy
Notepad is MS-Windows only and not likely to be used by developers (for whom this feature is intended).
Currently we don't support platform spesific presets so including simple text editors only available on spesific platforms seems like a bug (or paper cut) that needs to be fixed.
Most popular editors for scripts/code are cross platform so I'd rather limit editor presets to these.
Note: presets that don't make sense for a platform could be excluded by CMake (as part of the install target), in this particular case I'm not convinced it's worth including.
@ -0,0 +6,4 @@
match platform.system():
case 'Windows':
bpy.context.preferences.filepaths.text_editor = "code.cmd"
case other:
_
as the variable isn't used.@ -0,0 +30,4 @@
if not text_editor_args:
self.report(
{'ERROR_INVALID_INPUT'},
("Please provide the specific format of the arguments with which the text editor opens files."
Duplicating the documentation isn't necessary, either refer to the text editor arguments tool-tip, or - if you feel strongly that it's useful to include the message inline here, it can be accessed from RNA and included.
type(context.preferences.filepaths).bl_rna.properties["text_editor_args"].description
@ -0,0 +45,4 @@
from string import Template
import shlex
for plain_arg in shlex.split(text_editor_args):
arg = Template(plain_arg).substitute(file=self.filepath, line=self.line, column=self.column)
picky create a dictionary for
file=self.filepath, line=self.line, column=self.column
, then pass it as**template_vars
.This should also catch exceptions since references in the string to variables that don't exist raises an error.
e.g.
@ -0,0 +53,4 @@
# whit check=True if process.returncode !=0 a exception will be raised
process = subprocess.run(args, check=True)
return {'FINISHED'}
except subprocess.CalledProcessError as exception:
Catching a spesific exception means other exceptions will still cause errors that arent handled gracefully, for e.g. if the command isn't found a
FileNotFoundError
will be raised.except Exception as ex:
... should be sufficient.Requested changes inline.
Wouldn't it be better to do it in a sub-panel?
@ -0,0 +1 @@
import bpy
No need to capitalize file names (preset logic handles that).
Also, it seems including this file at all might be avoided, although I'd need to dig into details.
@ -0,0 +1,4 @@
import bpy
No need to capitalize file names (preset logic handles that).
@ -0,0 +1,10 @@
import bpy
code
is the name of the command, the application is "Visual Studio Code", naming the file:visual_studio_code.py
will display as expected.@ -0,0 +39,4 @@
template_vars = {"file": self.filepath, "line": self.line, "column": self.column}
try:
from string import Template
Move imports to the beginning of the function.
@ -0,0 +46,4 @@
self.report({'ERROR'}, "Exception parsing template: %r" % ex)
return {'CANCELLED'}
args.insert(0, text_editor)
picky prefer:
@ -0,0 +49,4 @@
args.insert(0, text_editor)
try:
import subprocess
move imports to beginning of the function.
@ -6507,0 +6519,4 @@
"$line Specifies the line where the cursor will be placed on. (Optional)\n"
"$column Specifies the character position within the $line where the cursor will be "
"placed. (Optional)\n\n"
"Ex: -f $file -l $line -c $column");
Use full text
Example:
Not sure of the best solution here, currently the editor & arguments read as if they might also be programs and are not so clearly related to the text editor, so a visual separation that groups these would be good.
@ -1405,0 +1422,4 @@
text_editor_label = text_editor
show_input = text_editor or preset_label == "Custom"
if show_input:
The "External:" prefix doesn't seem necessary, everything that isn't "Internal" is implicitly external.
it was removed because PresetPanel is now used
i moved the preferences to sub-panel, now it look like
I had to upload a commit just to remove the Internal.py file, because renaming it to internal.py didn't update.
Applied locally and noticed various issues, attached patch on this branch, also a patch on main (if that helps).
line0
,column0
(zero based variables), mainly useful forcolumn0
as some editors expect this.filepaths = bpy.context.preferences.filepaths
in presets.row.enabled
assignment.Requesting these changes are applied.
91d3de2949
to8e6d8b260f
UI: Add a custom Text Editorto UI: Add a custom text editor preferenceCommitted
e16ec95a16
with some minor corrections.WM_operator_properties_free(..)
.file
tofilepath
.Pull request closed