I'm looking for a way to move a line to the "next section" with SublimeText. It could be in the "next paragraph" if it's text (see below), in the "next node" if it's XML, in the "next code block" if it's code, etc.
Currently I'm using CTRLSHIFTDOWN ARROW many times to move it to the next section, but I think SublimeText might have this feature out-of-the-box.
Example of main use case:
§ion1
abcdef
ghijkl <--- if the cursor is in this line, pressing CTRL+DOWN would move this line...
sqfdsdfqsdfjq
§ion2 <--- ...here! just between "§ion2" and "Lorem".
Lorem ipsum dolor sit amet
&somethingelse <--- one more CTRL+DOWN would move it here
tempor incididunt ut labore et dolore magna aliqua
t enim ad minim veniam
quis nostrud exercitation
I finally managed to write a plugin for this:
# Put this file in "C:\Users\User\AppData\Roaming\Sublime Text 2\Packages\User\"
# Add this to "C:\Users\User\AppData\Roaming\Sublime Text 2\Packages\User\Default (Windows).sublime-keymap":
# { "keys": ["ctrl+up"], "command": "movesection", "args": {"direction": "up"}},
# { "keys": ["ctrl+down"], "command": "movesection", "args": {"direction": "down"}}
import sublime, sublime_plugin
import subprocess
class MovesectionCommand(sublime_plugin.TextCommand):
def run(self, edit, direction):
# select current line, save it and delete it
currentcursor = self.view.sel()[0].begin()
thisline = self.view.substr(self.view.full_line(currentcursor))
self.view.erase(edit, self.view.full_line(currentcursor))
# find the next/previous & and move there
if direction == 'down':
beg = self.view.sel()[0].begin()
end = self.view.size()
else:
beg = 0
end = self.view.sel()[0].begin()
contents = self.view.substr(sublime.Region(beg, end)) # https://stackoverflow.com/questions/20182008/sublime-text-3-api-get-all-text-from-a-file
offset = contents.find('&') if direction == 'down' else contents.rfind('&', 0, contents.rfind('&')) # down: first occurence, up: second-to-last occurence
cursors = self.view.sel()
cursors.clear()
location = sublime.Region(beg+offset, beg+offset)
cursors.add(location)
# move to the next line
(row, col) = self.view.rowcol(self.view.sel()[0].begin()) # go to the next line
self.view.run_command("goto_line", {"line": row+2})
# insert the text here
self.view.insert(edit, self.view.sel()[0].begin(), thisline)
# move to the line currently pasted (because of inserting the line usually including \n, it would go to next line, thus the following code is needed)
(row, col) = self.view.rowcol(self.view.sel()[0].begin())
self.view.run_command("goto_line", {"line": row})
Related
In the now obsoleted Autodesk ReCap API it was possible to specify a "bounding box" around the scene to be generated from images.
In the resulting models, any vertices outside the bounding box were discarded, and any volumes that extended beyond the bounding box were truncated to have faces at the box boundaries.
I am now using Autodesk's Forge Reality Capture API which replaced ReCap. Apparently, This new API does not allow the user to specify a bounding box.
So I am now searching for a program that takes an .OBJ file and a specified bounding box as input, and outputs a file of just the vertices and faces within this bounding box.
Given that there is no way to specify the bounding box in Reality Capture API, I created this python program. It is crude, in that it only discards faces that have vertices that are outside the bounding box. And it actually does discards nondestructively, only by commenting them out in the output OBJ file. This allows you to uncomment them and then use a different bounding box.
This may not be what you need if you truly want to remove all relevant v, vn, vt, vp and f lines that are outside the bounding box, because the OBJ file size remains mostly unchanged. But for my particular needs, keeping all the records and just using comments was preferable.
# obj3Dcrop.py
# (c) Scott L. McGregor, Dec 2019
# License: free for all non commercial uses. Contact author for any other uses.
# Changes and Enhancements must be shared with author, and be subject to same use terms
# TL;DR: This program uses a bounding box, and "crops" faces and vertices from a
# Wavefront .OBJ format file, created by Autodesk Forge Reality Capture API
# if one of the vertices in a face is not within the bounds of the box.
#
# METHOD
# 1) All lines other than "v" vertex definitions and "f" faces definitions
# are copied UNCHANGED from the input .OBJ file to an output .OBJ file.
# 2) All "v" vertex definition lines have their (x, y, z) positions tested to see if:
# minX < x < maxX and minY < y < maxY and minZ < z < maxZ ?
# If TRUE, we want to keep this vertex in the new OBJ, so we
# store its IMPLICIT ORDINAL position in the file in a dictionary called v_keepers.
# If FALSE, we will use its absence from the v_keepers file as a way to identify
# faces that contain it and drop them. All "v" lines are also copied unchanged to the
# output file.
# 3) All "f" lines (face definitions) are inspected to verify that all 3 vertices in the face
# are in the v_keepers list. If they are, the f line is output unchanged.
# 4) Any "f" line that refers to a vertex that was cropped, is prefixed by "# CROPPED: "
# in the output file. Lines beginning # are treated as comments, and ignored in future
# processing.
# KNOWN LIMITATIONS: This program generates models in which the outside of bound faces
# have been removed. The vertices that were found outside the bounding box, are still in the
# OBJ file, but they are now disconnected and therefore ignored in later processing.
# The "f" lines for faces with vertices outside the bounding box are also still in the
# output file, but now commented out, so they don't process. Because this is non-destructive.
# we can easily change our bounding box later, uncomment cropped lines and reprocess.
#
# This might be an incomplete solution for some potential users. For such users
# a more complete program would delete unneeded v, vn, vt and vp lines when the v vertex
# that they refer to is dropped. But note that this requires renumbering all references to these
# vertice definitions in the "f" face definition lines. Such a more complete solution would also
# DISCARD all 'f' lines with any vertices that are out of bounds, instead of making them copies.
# Such a rewritten .OBJ file would be var more compact, but changing the bounding box would require
# saving the pre-cropped original.
# QUIRK: The OBJ file format defines v, vn, vt, vp and f elements by their
# IMPLICIT ordinal occurrence in the file, with each element type maintaining
# its OWN separate sequence. It then references those definitions EXPLICITLY in
# f face definitions. So deleting (or commenting out) element references requires
# appropriate rewriting of all the"f"" lines tracking all the new implicit positions.
# Such rewriting is not particularly hard to do, but it is one more place to make
# a mistake, and could make the algorithm more complicated to understand.
# This program doesn't bother, because all further processing of the output
# OBJ file ignores unreferenced v, vn, vt and vp elements.
#
# Saving all lines rather than deleting them to save space is a tradeoff involving considerations of
# Undo capability, compute cycles, compute space (unreferenced lines) and maintenance complexity choice.
# It is left to the motivated programmer to add this complexity if needed.
import sys
#bounding_box = sys.argv[1] # should be in the only string passsed (maxX, maxY, maxZ, minX, minY, minZ)
bounding_box = [10, 10, 10, -10, -10, 1]
maxX = bounding_box[0]
maxY = bounding_box[1]
maxZ = bounding_box[2]
minX = bounding_box[3]
minY = bounding_box[4]
minZ = bounding_box[5]
v_keepers = dict() # keeps track of which vertices are within the bounding box
kept_vertices = 0
discarded_vertices = 0
kept_faces = 0
discarded_faces = 0
discarded_lines = 0
kept_lines = 0
obj_file = open('sample.obj','r')
new_obj_file = open('cropped.obj','w')
# the number of the next "v" vertex lines to process.
original_v_number = 1 # the number of the next "v" vertex lines to process.
new_v_number = 1 # the new ordinal position of this vertex if out of bounds vertices were discarded.
for line in obj_file:
line_elements = line.split()
# Python doesn't have a SWITCH statement, but we only have three cases, so we'll just use cascading if stmts
if line_elements[0] != "f": # if it isn't an "f" type line (face definition)
if line_elements[0] != "v": # and it isn't an "v" type line either (vertex definition)
# ************************ PROCESS ALL NON V AND NON F LINE TYPES ******************
# then we just copy it unchanged from the input OBJ to the output OBJ
new_obj_file.write(line)
kept_lines = kept_lines + 1
else: # then line_elements[0] == "v":
# ************************ PROCESS VERTICES ****************************************
# a "v" line looks like this:
# f x y z ...
x = float(line_elements[1])
y = float(line_elements[2])
z = float(line_elements[3])
if minX < x < maxX and minY < y < maxY and minZ < z < maxZ:
# if vertex is within the bounding box, we include it in the new OBJ file
new_obj_file.write(line)
v_keepers[str(original_v_number)] = str(new_v_number)
new_v_number = new_v_number + 1
kept_vertices = kept_vertices +1
kept_lines = kept_lines + 1
else: # if vertex is NOT in the bounding box
new_obj_file.write(line)
discarded_vertices = discarded_vertices +1
discarded_lines = discarded_lines + 1
original_v_number = original_v_number + 1
else: # line_elements[0] == "f":
# ************************ PROCESS FACES ****************************************
# a "f" line looks like this:
# f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...
# We need to delete any face lines where ANY of the 3 vertices v1, v2 or v3 are NOT in v_keepers.
v = ["", "", ""]
# Note that v1, v2 and v3 are the first "/" separated elements within each line element.
for i in range(0,3):
v[i] = line_elements[i+1].split('/')[0]
# now we can check if EACH of these 3 vertices are in v_keepers.
# for each f line, we need to determine if all 3 vertices are in the v_keepers list
if v[0] in v_keepers and v[1] in v_keepers and v[2] in v_keepers:
new_obj_file.write(line)
kept_lines = kept_lines + 1
kept_faces = kept_faces +1
else: # at least one of the vertices in this face has been deleted, so we need to delete the face too.
discarded_lines = discarded_lines + 1
discarded_faces = discarded_faces +1
new_obj_file.write("# CROPPED "+line)
# end of line processing loop
obj_file.close()
new_obj_file.close()
print ("kept vertices: ", kept_vertices ,"discarded vertices: ", discarded_vertices)
print ("kept faces: ", kept_faces, "discarded faces: ", discarded_faces)
print ("kept lines: ", kept_lines, "discarded lines: ", discarded_lines)
Unfortunately, (at least for now) there is no way to specify the bounding box in Reality Capture API.
Does anyone know of a shortcut for jumping to a specific line (given a #) in Sublime Text?
Ex: I run code and get an error at line 5765. I want to be able to jump quickly in Sublime Text to line 5765, without scrolling.
Windows: Ctrl + G
Mac: Control + G
Linux:Ctrl + G
or
Windows: Ctrl + P + :
Mac: Command + P + :
Linux: Ctrl + P + :
Then type the line number. It will automatically find it for you and if it requires scrolling to get to - it will snap your view to the line number level.
Rather than Control+G, if you're used to using CMD+P or CMD+T, you can just type :
Also useful:
CMD+R go to function in current file
CMD+Shift+R find function in any file (CMD+, "binary_file_patterns" ignore node_modules)
CMD+Option+Down jump to function definition in another file (from cursor word)
CMD+D / CMD+U jump & accumulate next word occurrence & populate search query / (undo). from cursor becomes an exact match (case and word boundary) vs from selection is a partial match (ignore case and word boundary). D and U also work in less bash / zshell pager to scroll down / up half pages
CMD+G / CMD+Shift+G jump or "go" to next / previous search query (CMD+D amazing with this)
CMD+{ / CMD+} focuses left / right tab (same in terminals, browser, kapeli dash, etc.)
CMD+[ / CMD+] shift line left / right (chrome forward / backward nav, devtools changes panel)
CMD+Control+Up / CMD+Control+Down shift line up / down
CMD+K->(some number) fold to indentation
CMD+K->J unfold all
CMD+Option+[ / CMD+Option+] fold / unfold current line's children
CMD+, is preferences in most all Mac applications
As pointed out by #maxTuzz, I use Ubuntu 16.06 and Sublime regularly,
this Ctrl+P then Pressing : and Starting typing the Line Number you want to Navigate.
Or
Directly we can type Ctrl+G Starting typing the Line Number you want to Navigate.
In My Mac, Performance>>Key Bindings add:
//line duplicate & delete
{ "keys": ["super+y"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Delete Line.sublime-macro"} },
{ "keys": ["super+d"], "command": "duplicate_line" },
//replace
{ "keys": ["super+r"], "command": "show_panel", "args": {"panel": "replace", "reverse": false} },
//goto
{ "keys": ["super+l"], "command": "show_overlay", "args": {"overlay": "goto", "text": ":"} },
{ "keys": ["super+g"], "command": "show_overlay", "args": {"overlay": "goto", "text": "#"} },
//upper or lower
{ "keys": ["super+shift+u"], "command": "swap_case" },
//sidebar toggle
{ "keys": ["super+shift+t"], "command": "toggle_side_bar" },
base is to press Ctrl + P and a then type : and then write the line that you want to go , BUT there is a shortcut for this :
Just hit Ctrl + G , and it does the same steps for you!
on your keyboard click the:
command + p
then type : on your keyboard follow by the line number, example 374
:374
then click the enter key on your keyboard to jump to the desired line number
Often I find myself doing repetitive file & replace operations in a file. Most often that comes down to fixed find and replace operations; deleting some lines, changing some strings that are always the same and so on.
In Vim that is a no-brainer,
function! Modify_Strength_Files()
execute':%s/?/-/'
execute':%s/Ä/-/'
"--------------------------------------------------------
execute':%s/Ä/-/'
execute':%s///g'
"--------------------------------------------------------
execute':g/Version\ of\ Light\ Ship/d'
execute':g/Version\ of\ Data\ for\ Specific\ Regulations/d'
"--------------------------------------------------------
" execute':g/LOADING\ CONDITION/d'
" execute':g/REGULATION:\ A\.562\ IMO\ Resolution/d'
" This is to reduce multiple blank lines into one.
execute ':%s/\s\+$//e'
execute ':%s/\n\{3,}/\r\r/e'
" ---------------------
endfunction
copied verbatim.
How could a function like this be defined in Sublime Text editor, if it can be done at all, and then called to act upon the currently opened file?
Here are resources to write Sublime Text 2 plugins:
Sublime Text 2 API Reference
Sublime Text 2 Plugin Examples
How to run Sublime Text 2 commands
Setting up Sublime Text 2 Custom Keyboard Shortcuts
Example: you can write a similar plugin and bind a hot key to it, that is, batch_edit command. Then you can open a file and execute the command via that hot key. By the way, in this script, I didn't consider the file encoding. You can get the file encoding via self.view.encoding().
# -*- coding: utf-8 -*-
import sublime, sublime_plugin
import re
class BatchEditCommand(sublime_plugin.TextCommand):
def run(self, edit):
self._edit = edit
self._replace_all(r"\?", "-")
self._replace_all(u"Ä", "-")
self._delete_line_with(r"Version of Light Ship")
self._delete_line_with(r"Version of Data for Specific Regulations")
self._replace_all(r"(\n\s*\n)+", "\n\n")
def _get_file_content(self):
return self.view.substr(sublime.Region(0, self.view.size()))
def _update_file(self, doc):
self.view.replace(self._edit, sublime.Region(0, self.view.size()), doc)
def _replace_all(self, regex, replacement):
doc = self._get_file_content()
p = re.compile(regex, re.UNICODE)
doc = re.sub(p, replacement, doc)
self._update_file(doc)
def _delete_line_with(self, regex):
doc = self._get_file_content()
lines = doc.splitlines()
result = []
for line in lines:
if re.search(regex, line, re.UNICODE):
continue
result.append(line)
line_ending = {
"Windows" : "\r\n",
"Unix" : "\n",
"CR" : "\r"
}[self.view.line_endings()]
doc = line_ending.join(result)
self._update_file(doc)
Sublime text 2 (Windows 7) has such feature: several lines with carets (no selections made,only carets) are copied to Clipboard separated with empty lines. Can i disable these empty line separators, to copy w/o them?
detail:
open few lines text file
place 3-4 carets using Ctrl+Click on few lines
press Ctrl+C to copy to clibboard
paste into new file-- u see empty line separators for copied text
Think you need a plugin to do it. I didn't test this, but it should work. It's pretty straight forward.
import sublime
import sublime_plugin
class EmptyLineCopyCommand(sublime_plugin.TextCommand):
def run(self, edit):
view = self.view
lines = []
for cursor in view.sel():
lines.append(view.substr(view.line(cursor)))
sublime.set_clipboard("\n".join(lines))
Put the following in your user key bindings.
{"keys": ["ctrl+c"], "command": "empty_line_copy", "context": [
{ "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }
]},
Is there a way to add insert a number that is incremented once per cursor in Sublime Text 2?
Example, with | as the cursor:
Lorem ipsum dolor sit amet, |
vehicula sed, mauris nam eget|
neque a pede nullam, ducimus adipiscing,
vestibulum pellentesque pellentesque laoreet faucibus.|
Desired result:
Lorem ipsum dolor sit amet, 1|
vehicula sed, mauris nam eget2|
neque a pede nullam, ducimus adipiscing,
vestibulum pellentesque pellentesque laoreet faucibus.3|
Does this functionality exist natively, or is there a plugin providing it?
I recommend the plugin Text Pastry. The Number Sequence command is the one you need.
I prefer to use the Insert Nums command:
Text Pastry has a build in support for the Insert Nums syntax by
providing three numbers separated by one space:
N M P
N: the start index.
M represents the step size which will be added to the index for
each selection.
P must be > 0 and will be used to pad the index with
leading zeroes.
I think that the only way to achieve what you ask is to create your own plugin.
Tools/New Plugin...:
import sublime_plugin
class IncrementSelectionCommand(sublime_plugin.TextCommand):
def run(self, edit):
start_value = int(self.view.substr(self.view.sel()[0]))
counter = 0
for selection in self.view.sel():
self.view.insert(edit, selection.begin(), str(start_value + counter))
counter = counter + 1
for selection in self.view.sel():
self.view.erase(edit, selection)
Save it in your User directory.
Then add a shortcut to your Key Bindings - User:
{ "keys": ["YOUR_SHORTCUT"], "command": "increment_selection" }
Now you can place the cursors where you need:
Insert the number the counter should start from (in this case 1):
Select the number you typed (shift<—):
Type the shortcut:
You want to had a number at each row that you have selected, but not the same. For exemple, you select 5 cursors and you want to write 1 2 3 4 5.
select your 5 cursors maybe you can use ctrl + maj + L on the highlighted lines
ctrl + maj + P and select arithmetic
Because you have 5 cursors, it propose 1 2 3 4 5
If you want you can change your number of iteration
Or start from an other number than 1
Add odd number