Do you mean using one of your packages, or in the base install? From what I understand you have implemented a lot of the stuff I talk about above in a package.
API Suggestions
I extract the styles similar to your example for my ColorSchemeUnit package.
An API would be good.
The current relevant code is (needs optimising):
class Style(object):
def __init__(self, view):
self.view = view
self.parse_color_scheme_file(self.view.settings().get('color_scheme'))
def at_point(self, point):
return self.get_styles_for_scope(self.view.scope_name(point).strip())
def parse_color_scheme_file(self, color_scheme_file):
color_scheme_content = sublime.load_resource(color_scheme_file)
color_scheme_dict = plistlib.readPlistFromBytes(bytes(color_scheme_content, 'UTF-8'))
self.selectors_in_scheme = color_scheme_dict['settings']
def get_styles_for_scope(self, scope):
styles = dict()
for scheme_selector in self.selectors_in_scheme:
if 'scope' not in scheme_selector:
styles.update(scheme_selector['settings'])
matched_style = {'settings': {}, 'score': 0}
for scheme_selector in self.selectors_in_scheme:
if 'scope' in scheme_selector:
score = sublime.score_selector(scope, scheme_selector['scope'])
if score:
if score >= matched_style['score']:
matched_style['score'] = score
matched_style['settings'].update(scheme_selector['settings'])
styles.update(matched_style['settings'])
return styles
Yes. I have a couple of plugins that use some of the same color libs: ExportHtml, ScopeHunter, ColorHelper, and the mdpopups dependency. The idea is to create one dependency they use and make it available to anyone else as well. Though mdpopups will be harder move to a color lib dependency as it is a dependency itself, and Package Control can’t specify dependencies for dependencies. Getting people who use mdpopups to migrate to using that color dependency will be more slow as I have to give people time realize the change is occurring and adapt.
Anyways, the idea is to clean up the code and provide a more sane API. I would just bundle the various color stuff as a dependency lib. That way my plugins will just use a shared dependency instead of all shipping the same/similar libraries as they do now.
I would change unnecessary things like ColorSchemeMatcher.guess(view, pt, scope)
to something like you suggested above ColorSchemeMatcher.guess(scope, selected=True)
(which I like), and it would provide you with the a style object with colors, emphasis, transparent colors converted to non-transparent colors (since the Sublime CSS engine doesn’t really handle the color mixing stuff), etc. And you could then also request special colors like gutter, selection, foreground, and background directly like this: ColorSchemeMatcher.get_special_color('selectionForeground', simulated_transparency=True)
. Not sure if I care about including access to stuff like activeGuide
etc. as I don’t find that stuff useful, but maybe.
I think I would also throw in the library to adjust the colors, brightness, saturation, etc. I would throw in the colorbox library that can generate color boxes for sublimes HTML content. Maybe even provide access to a call to convert a scheme to CSS using standard TextMate scopes. Stuff like that. Then if I add more, everyone using the lib would get access to those things too.
I’m not sure yet how I feel about implementing a CSS parser though. I have no problem with providing access to the CSS though. People could put anything in there. And you still don’t get what Sublime is providing under that layer. Luckily, in its currently implementation, you have to keep things simple. You can’t really specify div.class
or .class1 .class2
(or you couldn’t last I checked – I don’t know if things changed). All you can really do right now is element
and .class
and .class1.class2
. But if any of that changes, things break and then get more complicated to parse.
I don’t feel like it is practical to scan for everything in the CSS. The only time I really care about scanning for weird scopes in a scheme is when I am replicating a Sublime View in HTML, and I only need to that for creating code blocks from Sublime in HTML, and for something like ScopeHunter. I don’t really need to replicate CSS in my sub CSS for popups and phantoms; I should already get that stuff for free as long as I don’t override it. I don’t want to scan for available classes either. I just want to know what standard classes are reasonably expected to be there. Whatever non-standard class you are looking for could be missing if you install another scheme. From a plugin standpoint, I would only be interested in what standard class names I can use, and maybe the body
element back-ground color for when I insert images. I would prefer that themes keep that stuff simple so I don’t have to do elaborate analysis.
The reason why I wrote mdpopups
was to standardize everything for myself and the plugins I write to spare myself from analyzing scopes in every plugin for popups; it’s all done for me. I just give it scopes and don’t worry about. If I need something specific, I inject a little additional CSS using known scopes. I know I can only expect standard TextMate scopes and .foreground
and .background
. I know that mdpopups
will make the background and foreground color the same as the scheme background and the foreground. So it is a simple list I can reference. I now know that schemes are likely to include colors and font styling under the classes .error
, .deleted
, .success
, .inserted
, .warning
, and .modified
. I don’t care if a theme inserts other classes as those will vary from theme to theme and can’t be relied on. I am only interested in standard colors. I’d rather give up a little control to have things consistent.
scrolloff and sidescrolloff similar to vim
*'scrolloff'* *'so'*
'scrolloff' 'so' number (default 0)
global
{not in Vi}
Minimal number of screen lines to keep above and below the cursor.
This will make some context visible around where you are working. If
you set it to a very large value (999) the cursor line will always be
in the middle of the window (except at the start or end of the file or
when long lines wrap).
For scrolling horizontally see 'sidescrolloff'.
NOTE: This option is set to 0 when 'compatible' is set.
*'sidescrolloff'* *'siso'*
'sidescrolloff' 'siso' number (default 0)
global
{not in Vi}
The minimal number of screen columns to keep to the left and to the
right of the cursor if 'nowrap' is set. Setting this option to a
value greater than 0 while having |'sidescroll'| also at a non-zero
value makes some context visible in the line you are scrolling in
horizontally (except at beginning of the line). Setting this option
to a large value (like 999) has the effect of keeping the cursor
horizontally centered in the window, as long as one does not come too
close to the beginning of the line.
NOTE: This option is set to 0 when 'compatible' is set.
Example: Try this together with 'sidescroll' and 'listchars' as
in the following example to never allow the cursor to move
onto the "extends" character:
:set nowrap sidescroll=1 listchars=extends:>,precedes:<
:set sidescrolloff=1
In addition to this, it would be great if add_regions()
properly supported making text bold or italic as specified by the “fontStyle” setting in color schemes.
An alternative to this might be just to provide some way to programmatically change the scope of any region of text. Given the fact that add_regions()
doesn’t actually change scope and its weird behavior when either the background or both foreground and background of a scoped setting in a color scheme match those of the global setting or are absent, this could definitely prove a useful addition, as text colored by the scopes specified by syntax files don’t suffer from these problems.
Also, it seems others have expressed interest in such a feature.
In the View API there is:
find_by_class(point, forward, classes, <separators>)
that “finds the next location after point that matches the given classes.” where classes can detect word/line start/end and punctuation.
I’d like a similar API with scope selectors instead of classes.
There is find_by_selector(selector)
but it returns the list of all the matching regions in the file, while I only need the next one matching.
It would be super nice to expose the dictionary related stuff, so we can spell check many languages at the same time in a single document
Just to extend this a bit further, how about the ability to to also change the line color in the minimap, also like in Atom?
A save command without side-effects
It would be nice to have a save command that does not produce any side effects, but only saves the view/buffer to file.
Currently, the save command is customized for for the use case where the user asks for the file to be saved, typically by pressing cmd+s (or ctrl+s). However, this action has side effects other than just saving the file. Most prominently, the save command will close auto-complete panels.
The problem: While the side-effects make sense when save is requested by the user, they make life harder for plugin developers who would like to save the file without closing auto-complete panels (or invoking other side effects). The auto-save package is one example of a plugin that has had to develop overly-complex solutions to work around the side effects of the save command.
The solution: Add the ability in the API to save the buffer without invoking side effects. It doesn’t matter too much exactly how this is done - whether via a completely new command, or through a keyword argument to the existing save command.
Importance: Minor (but also simple to implement…)
Notes (based on other comments):
- Writing directly to file without using ST’s API doesn’t work well, since users get “File has changed on disk” messages every time the file is auto-saved (depending on their configuration). Doing things “the right way” means saving the view/buffer using Sublime’s API.
Make More Types of Overlay Available to Plugin Developers
Importance: Major
Sublime Text has 5 distinct types of overlays, each with slightly different styles and capabilities. They are:
- Command Palette
- Show Files
- Goto ‘Anything’ : Symbol / Line Number / Term
- Goto Symbol In Project
- Quick Switch Project
I propose that all of the styles and capabilities of these overlays be made available to plugin developers, either via the existing API Window
class show_quick_panel()
method or by the addition of a variety of show_xxx_panel()
methods.
This would be a wonderful addition to the API, please consider it.
Proposed Overlay Additions To The API
-
A Two Column Overlay; like Command Palette
-
A Free Standing Overlay; like Quick Switch Project
- The overlay is displayed in its own custom centered ‘dialog’ box / window
- The overlay keeps the focus until a row is selected or it is cancelled
-
Flags to control the Width of the overlay
- Auto-Expand Width;
show_quick_panel()
bug fix needed, not working properly with 80% of themes - Wide Width; like Command Palette, Show Files, and Goto ‘Anything’
- Medium Width; like Goto Symbol In Project
- Narrow Width; e.g. for showing a list of numbers, etc.
- Extra Wide Width; e.g. for showing long paths at regular font size
- If not enough room to show the text, width should auto-expand
- Possibly mutually exclusive flags:
AUTO_EXPAND_WIDTH
andTRUNCATE_TEXT_AT_WIDTH_LIMIT
- Auto-Expand Width;
-
Flags to control the Font Size
- Regular Font Size; like Command Palette, Show Files, and Switch Project
- Small Font Size to allow more visible rows; like Goto ‘Anything’
-
A flag to set NO initially selected row; like Show Files
- Or achieve this implicitly by setting
selected_index
to-1
- Or achieve this implicitly by setting
-
A flag to prevent ST from stripping trailing whitespace
- To allow indentation/padding to be added to the right side of rows as well as on the left
- Alternatively indentation flags to achieve the same thing
- So that the same style as Show Files indentation can be achieved
-
A method parameter to set the text in the overlay’s input box; like Goto ‘Anything’, and Command Palette
- The
show_input_panel()
API method does this with itsinitial_text
parameter - No initial text if set to an
""
empty string -
initial_text
should be given to the awesome ST fuzzy matching so that only matching rows get displayed - Flag to make
initial_text
selected; like Command Palette does when it shows the most recently used text
- The
Have I missed anything that others would like?
Many thanks.
Dev Build 3154
Why not just open and write to a file handle using python?
Because if you write the file to disk manually then users get repeated “File has changed on disk” messages (depending on their configuration). Doing things “the right way” means saving the view/buffer using Sublime’s API.
Clear the console.
sublime.clear_console()
I know it’s not really important, but when you create plugin, it would help to keep a scrollbar larger than 1px
Matt
Hello @wbond,
I am working on a search plugin. For reference the UX is currently defined like this plugin: https://github.com/krasun/SublimeInternetSearch
In order to make a search I have to open the input with show_input_panel
then make a request and finally populate search results with the show_quick_panel
API.
From a user perspective, they are searching in the input (bottom left of the screen) and then getting results in the middle. With a field to further filter results but that doesn’t work for new searches.
That makes the user flow very clunky.
Would be awesome if we could have the same callback that we have on the input_panel with the show_quick_panel with access to the user input and the ability to modify the list on user input (bypass the match).
In a summary I would love:
- Access to the user input of the quick_panel
- Bypass the match of that field
Importance: Major
Difficulty: Should be pretty easy for you.
Thank you !
- Tabbed side bars for the same project so that one could switch contexts without changing windows.
- window.open_project with arguments for specific folder OR file.
- view.set_title() similar to view.set_status()
- window.set_minimap_scopes() so that the minimap can show a filtered summary
A function to check if a view is currently visible would be helpful in some situations, to check whether a plugin needs to update a view or not.
view.is_visible()
The function should return true, if the view is the active one in any group. For now I implement it like this, but I think it should be part of the View class as well as all the other new is_..._visible
methods.
def is_view_visible(view):
"""Return true if the view is visible.
Only an active view of a group is visible.
Note: this should be part of the View class but it isn't.
"""
w = view.window()
return any(view == w.active_view_in_group(g)
for g in range(w.num_groups())) if w is not None else False
is_visible
has fuzzy meaning though. What if it’s active but window is entirely covered by other window? Is it still visible then? Might be better to just call it is_active
which would imply “in group”.
The “active view” is, by convention, the view in the window that has focus (or most recently had focus if a panel is open). This is what Window.active_view
returns at least. By the way, that also works for inactive windows.
I also wouldn’t care about the window being covered by other windows, most specifically because ST wouldn’t even know this, so is_visible
is fine.