Snippets where content is conditional on language in Sublime Text 3? - sublimetext

Is there a way to create a single snippet file where the content output is dependent on the language? For example, keyboard shortcut x outputs "abc" when used in a css file, but "def" when used in a javascript file?

Snippets don't contain much processing capability — you can perform substitutions in them via Boost-style regexes and format strings, and they have access to a number of environment variables within Sublime such as the current file's name, the line number, etc., but beyond that they don't have much programmatic processing capability. It might be possible to set up a series of regexes that try to case-insensitively match $TM_FILENAME against \.css$ and output abc, then immediately match $TM_FILENAME against \.js$ and output def - only one of them will be successful.
However, in my mind such processing is much more easily handled by a plugin written in Python. The API documentation is mostly complete (all the functions you'll need are documented there) and there are a ton of examples around the net to learn/borrow from. Here's a quick example:
import sublime_plugin
class PrintScopeCommand(sublime_plugin.TextCommand):
def run(self, edit):
pos = self.view.sel()[0].begin()
scope = self.view.scope_name(pos)
if 'source.js' in scope:
self.view.insert(edit, pos, "This is JavaScript!")
elif 'source.css' in scope:
self.view.insert(edit, pos, "This is CSS!")
Save the file in your Packages/User directory (accessible via Preferences -> Browse Packages...) as print_scope.py. Next, assign it to a key binding by opening your user keymap (Preferences -> Key Bindings-User) and adding the following:
[
{ "keys": ["ctrl+alt+shift+p"], "command": "print_scope" }
]
if the file is empty. If you already have other custom key bindings, just add a comma , after the last one, then paste the line above after it, before the closing square bracket ].
You should now be able to hit CtrlAltShiftP (or whatever other key binding you choose), and if the file's syntax is set to JavaScript it will insert the This is JavaScript! message at the current cursor position. If the syntax is set to CSS, This is CSS! will print, and if the syntax is anything else, then nothing will print.

Related

How to disable sublime text 4 Context-Aware Suggestions

In sublime text 4, it will suggest context word, I want disable that feature.
for example, I type wh, I will get a "while snippet".
when file have "while" word, I type wh,I will get "while" word and "while snippet",I have to move down to select "while snippet".
"auto_complete_use_index": false, do not work.
Is there a way to disable the first "while" word.
If you don't want to inhibit word/buffer completions entirely, you can create a plugin like the following (Tools menu -> Developer -> New Plugin... and replace the placeholder with the following):
import sublime, sublime_plugin
class InhibitWordCompletionsEventListener(sublime_plugin.EventListener):
def on_query_completions(self, view, prefix, locations):
return sublime.CompletionList([sublime.CompletionItem.command_completion('', 'noop')], sublime.INHIBIT_WORD_COMPLETIONS)
Be sure to save it in the folder ST recommends (i.e. Packages/User/) with a .py extension.
Then, when you type wh, ST won't suggest the word while, just the Python snippet.
NOTE: this feels like a bit of a hack, it may not work this way in future builds of ST, but I tested on 4125 and it works there.
If you do want to disable buffer completions entirely, see How to remove words in the current buffer from Sublime Text 4 autocomplete list.
On my test for version 4121,I get the following results:
"auto_complete_include_snippets": false, --OK
"auto_complete_use_index": false, -- no work
"index_files": false, -- no work
Given this, you can try the setting:
"auto_complete_include_snippets"

Scripting Word from vbs

I'm trying to get Word to fill in cells in a table. The script works when run as a macro from within Word, but fails when saved as a .vbs file and double-clicked, or run with wscript. This is a part of it.
set obj = GetObject(,"Word.Application)
With obj
With .Selection
MsgBox .text
If (.Information(wdWithInTable) = True) Then
.Collapse Direction:=wdCollapseStart
tCols = .Tables(1).Columns.Count
tRow = .Information(wdStartOfRangeRowNumber)
tCol = .Information(wdStartOfRangeColumnNumber)
For I = 2 To 5
.Tables(1).Cell(tRow, I).Range.Text = "fred" & Str(I)
Next
` now make new row
For I = 1 To tCols - tCol + 1
.MoveRight unit:=wdCell
Next
End If
End With
End With
I have three problems. First, it won't compile unless I comment out the .Collapse and .MoveRight lines. Second, although the MsgBox .text displays the selected text, I get "out of range" errors if I try to access any .Information property.
I'm sure I'm missing something very simple: I usually write software for Macs, and I'd do this using AppleScript. This is my first attempt at getting anything done under Windows.
VBScript and VBA are different languages.
They are a bit similar, but not very. Moreover, VBScript is not like AppleScript; it doesn't let you easily interface with running programs.
The interfaces you'll get from VBScript can behave subtly differently in VBA and VBScript. However, I think you've got two problems here:
:= is invalid syntax in VBScript; you'll need to find an alternative way of calling the function. Try just using positional arguments.
You've no guarantee that this will open the expected file; there could be another instance of Word that it's interacting with instead.
Since your code is not running within the Word environment it would require a reference to the Word object library in order to use enumeration constants (those things that start with wd).
VBScript, however, cannot work with references, which means the only possibility is to use the long value equivalents of the enumerations. You'll find these in the Word Language References. Simplest to use is probably the Object Browser in Word's VBA Editor. (In Word: Alt+F11 to open the VBA Editor; F2 to start the Object Browser; type in the term in the "Search" box, click on the term, then look in the bottom bar.)
The code in the question uses, for example:
wdWithInTable
wdCollapseStart
wdStartOfRangeRowNumber
wdStartOfRangeColumnNumber
wdCell
The reason you get various kinds of errors depends on where these are used.
Also, VBScript can't used named parameters such as Unit:=. Any parameters must be passed in comma-delimited format, if there's more than one, in the order specified by the method or property. If there are optional parameters you don't want to use these should be left "blank":
MethodName parameter, parameter, , , parameter

Get Automator app result in external Applescript?

Is there a way to retrieve result of an Automator app script in an external Applescript app (not the Applescript lines in Automator)?
Something like:
tell application "My_Automator_App"
-- suppose My_Automator_App checks the Calendar to see if there some events today
-- "Show Result" in Automator will display a list
get the_Result -- list returned by Automator
end tell
I looked into this a little bit and didn't find a natural means by which AppleScript and Automator applets can communicate, although this doesn't mean one definitely doesn't exist.
In the meantime, you could implement one of a couple of workarounds/hacks that, although a little unseemly in their methods, do achieve the desired result without creating any side issues that would affect the functionality of an applet itself.
1. Use The Clipboard
Append a Copy to Clipboard action at the end of the applet's workflow, or following the action whose result you would wish to be reported.
Retrieving the clipboard from AppleScript is simple:
get the clipboard
This will probably suit return values that are simple text strings or a number. Passing an array of items from an Automator action to the clipboard isn't very reliable, sometimes only allowing access to the first item. However, this can be resolved with a small AppleScript within the workflow to process results arrays properly and convert them into an accessible format, e.g. a comma-delimited string.
However, the clipboard is also capable of storing image data, file references, and other data types, so it will be possible (if not always straightforward) to send those to be retrieved in an AppleScript.
Where possible, strings and numbers are the safest storage types.
2. Write Out To A Temporary File
To avoid using the clipboard as an intermediary, or if you wish the applet to report multiple variables without too much work, then writing the data to a temporary file is a fairly common practice, such as is done in shell scripts when persistant values are needed between multiple executions of the same script.
There's actually a special directory that gets periodically purged so that temporary data files don't accumulate: /tmp. It's hidden in Finder, but you can still create files and delete them as you would any other directory. Files that aren't access for 3 days get purged by the system.
There is a New Text File action that can write text to a file:
Specifying the /tmp directory is most easily done by creating a variable whose value is "/tmp" (without the quotes), and dragging that variable onto the appropriate field.
But my inclination would be to insert an AppleScript, or more suitably, a shell script into the workflow, with which file manipulation becomes easy and more capable.
Calendar Events Example
Using a similar example to the scenario you described, a simple applet that retrieves calendar events might have a workflow that looks like this:
where you can calibrate the first action to isolate the events you want, such as today's events. That action returns a type of object that isn't easily processed by AppleScript, but the second action extracts the relevant data in text format, summarising the list of events that the first action returned.
This is where a temporary file is useful to write out the data to a text file, which can then be retrieved in an AppleScript.
Given this Automator applet saved under the named "CalEvents", this AppleScript makes use of that applet and its result:
property tidEvents : [linefeed, linefeed, "EVENT", space] as text
property tidDetails : {tab, " to "}
property tid : a reference to my text item delimiters
run application id "com.apple.automator.CalEvents"
set tid's contents to tidEvents
set EventsSummary to read POSIX file "/tmp/EventsSummary.txt"
set EventsList to the EventsSummary's text items
set [[n], EventsList] to [it, rest] of EventsList
set n to n's last word as number
EventsList -- The final list of events from first to last
Upon its first run, the applet requires consent to access your calendar information, which only needs to be done once and will make the above script appear to fail. Once authorised, you can run the script as often as you like to get the most up-to-date content of the /tmp/EventsSummary.txt file.
Each item in the list variable EventsList is a block of text that looks like this (asterisks are my redactions for privacy, as are the address items in curly braces):
4 OF 8
Summary: GP Appointment
Status: none
Date: 07/12/2017 to 07/12/2017
Time: 14:45:00 to 15:45:00
Location: ******** Medical Centre
{Address Line 1}
{Address Line 2}
{County}
{Post Code}
United Kingdom
Notes: 01*** *****9
Each value is separated from the preceding colon by a tab character, which won't be obvious here. Also, as you can tell from the date format and address, these are British-formatted values, but yours will, of course, be whatever they are set as in Calendar.
But since each list item is much the same, extracting details for a particular event will be simple in AppleScript, first by splitting a particular event item into paragraphs, and then splitting a particular paragraph by either a tab or space character (or both) or some preposition that naturally delimits useful bits of text:
set |Event| to some item in the EventsList
set tid's contents to tidDetails
set EventDetails to {title:text item 2 of paragraph 2 ¬
, startTime:text item 2 of paragraph 5 ¬
, EndTime:text item 3 of paragraph 5} of the |Event|
which places the important event details, such as its name and start/end times, in an AppleScript record:
{title:"GP Appointment", startTime:"15:45:00", EndTime:"16:00:00"}

How to read firefox's about:config entries using Python?

How could I read about:config entries for firefox version 30.0 using Python ? I tried to use what is pointed by this answer (in JavaScript) but it did not help.
Yeah, that's a problem. Firefox comes with default values for most preferences, and only stores values different from the default in the profile. Added to this, each add-on may come with additional default values and create new preferences at runtime.
The default pref files might be contained within zip files, which complicates matters a little.
Files
Files you'd have to check for default preferences (in a standard Firefox distribution)
$APPDIR/omni.ja:greprefs.js
$APPDIR/omni.ja:defaults/preferences/*.js
$APPDIR/browser/omni.ja:greprefs.js
$APPDIR/browser/omni.ja:defaults/preferences/*.js
$PROFILE/extensions/*/defaults/preferences/*.js
$PROFILE/extensions/*.xpi:defaults/preferences/*.js
While preferences that were overridden from the default reside in $PROFILE/prefs.js.
So first you need to figure out $APPDIR (installation path of Firefox) and then $PROFILE (Firefox user profile path).
Then you need to read some files either in some directories (easy) or in some zip files (hard). A major problem is that you cannot just use zipfile to read omni.ja (and potentially some of the xpi files) because a typical python zipfile implementation is too rigid in the interpretation of the zip structure and fails to open these files. So you'd need your own zipfile implementation that can deal with this.
Format
In the *.js files there are essentially two types of lines (+ blank lines, comment lines):
pref("name", value)
user_pref("name", value)
The pref lines are default preferences, user_pref lines are user preferences (overridden from default).
Values
value is a Javascript expression such as "abc", true, 1 or 2 * 3. The latter is a problem, as you'd need a JS engine to properly evaluate it. But this isn't really a problem in practice, as you won't find expressions computing something in the wild (usually).
Conclusion
Really replicating the preferences system (or about:config) isn't an easy task and full of obstacles. It is probably far easier just reading user pref.js to see what's overridden and knowing the default values.
Example (just prefs.js)
import re
import json
PROFILE = "/path/to/firefox/profile"
def read_user_prefs(preffile):
r = re.compile(r"\s*user_pref\(([\"'])(.+?)\1,\s*(.+?)\);")
rv = {}
for l in preffile:
m = r.match(l)
if not m:
continue
k, v = m.group(2), m.group(3)
try:
rv[k] = json.loads(v)
except Exception as ex:
print "failed to parse", k, v, ex
return rv
with open("{}/prefs.js".format(PROFILE), "rb") as p:
prefs = read_user_prefs(p)
for k, v in prefs.items():
print u"({type:<16}) {key}: {value}".format(
key=k, value=v, type=str(type(v)))
print
print "Chrome debugging enabled:",
print prefs.get("devtools.chrome.enabled", False)
print "Last sync:",
print prefs.get("services.sync.tabs.lastSync", 0.0)
print "Pref that might not exist:",
print prefs.get("does.not.exist", "default")
Alternatives
Write a firefox-addon that dumps interesting Preferences to a known file, or uses another form of IPC (sockets, whatever) to communicate with your python script.

Reformatting text (or, better, LaTeX) in 80 colums in SciTE

I recently dived into LaTeX, starting with the help of a WYSIWYM editor like Lix. Now I'm staring writing tex files in Sci-TE, It already has syntax higlighting and I adapted the tex.properties file to work in Windows showing a preview on Go [F5]
One pretty thing Lyx does, and it's hard to acheive with a common text editor, is to format text in 80 columns: I can write a paragraph and hit Return each time I reach near the edge column but if, after the first draft, I want to add or cut some words here and there I end up breaking the layout and having to rearrange newlines.
It would be useful to have a tool in Sci-TE so I can select a paragraph of text I added or deleted some words in and have it rearranged in 80 columns. Probably not something working on the whole document since it could probably break some intended anticipated line break.
Probably I could easily write a Python plugin for geany, I saw vim has something similar, but I'd like to know if its' possible in Sci-TE too.
I was a bit disappointed when I found no answer as I was searching for same. No helpers by Google either, so I searched for Lua examples and syntax in a hope to craft it myself. I don't know Lua so this can perhaps be made differently or efficiently but its better then nothing I hope - here is Lua function which needs to be put in SciTE start-up Lua script:
function wrap_text()
local border = 80
local t = {}
local pos = editor.SelectionStart
local sel = editor:GetSelText()
if #sel == 0 then return end
local para = {}
local function helper(line) table.insert(para, line) return "" end
helper((sel:gsub("(.-)\r?\n", helper)))
for k, v in pairs(para) do
line = ""
for token in string.gmatch(v, "[^%s]+") do
if string.len(token .. line) >= border then
t[#t + 1] = line
line = token .. " "
else
line = line .. token .. " "
end
end
t[#t + 1] = line:gsub("%s$", "")
end
editor:ReplaceSel(table.concat(t, "\n"))
editor:GotoPos(pos)
end
Usage is like any other function from start-up script, but for completness I'll paste my tool definition from SciTE properties file:
command.name.8.*=Wrap Text
command.mode.8.*=subsystem:lua,savebefore:no,groupundo
command.8.*=wrap_text
command.replace.selection.8.*=2
It does respect paragraphs, so it can be used on broader selection, not just one paragraph.
This is one way to do it in scite: first, add this to your .SciTEUser.properties (Options/Open User Options file):
# Column guide, indicates long lines (https://wiki.archlinux.org/index.php/SciTE)
# this is what they call "margin line" in gedit (at right),
# in scite, "margin" is the area on left for line numbers
edge.mode=1
edge.column=80
... and save, so you can see a line at 80 characters.
Then scale the scite window, so the text you see is wrapped at the line.
Finally, select the long line text which is to be broken into lines, and do Edit / Paragraph / Split (for me the shortcut Ctrl-K also works for that).
Unfortunately, there seems to be no "break-lines-as-you-type" facility in scite, like the "Line Breaking" facility in geany. not anymore, now there's a plugin - see this answer
Well, I was rather disappointed that there seems to be no "break-lines-as-you-type" facility in scite; and I finally managed to code a small Lua plugin/add-on/extension for that, and released it here:
lua-users wiki: Scite Line Break
Installation and usage instructions are in the script itself. Here is how SciTE may look when the extension properly installed, and toggle activated after startup:
Note that it's pretty much the same functionality as in geany - it inserts linebreaks upon typing text - but not on pressing backspace, nor upon copy/pasting.
the same but more easy, I think...
put this in the user properties:
command.name.0.*=swrap
command.0.*=fold -s $(FileNameExt) > /tmp/scite_temp ; cat /tmp/scite_temp >$(FileNameExt)
command.is.filter.0.*=1
Ciao
Pietro

Resources