.. include:: /include/substitutions.txt .. include:: /include/external_links.txt .. include:: /include/custom_roles.txt .. _editing: ******* Editing ******* .. _layouts: Layouts ******* Before we get into keyboard editing, let us first consider how you might want your Sublime |nbsp| Text :term:`Editing Panel` laid out. Sublime Edit implements a remarkably flexible layout engine, very similar to the CSS Grid Layout engine. In addition to these default Key Bindings that set up different layouts that come with Sublime |nbsp| Text out of the box are: - ``alt+shift+1`` default (one :term:`Focus Group`) - ``alt+shift+2`` 2 side-by-side Focus Groups - ``alt+shift+3`` 3 side-by-side Focus Groups - ``alt+shift+4`` 4 side-by-side Focus Groups - ``alt+shift+5`` 2x2 grid of Focus Groups - ``alt+shift+8`` 2 Focus Groups, one above the other - ``alt+shift+9`` 3 Focus Groups, one above the other Of course, you could override these Key Bindings to suit your own needs. See :ref:`key binding definitions` for details. You can create custom layouts (e.g. in a WindowCommand in a :term:`Plugin`) by calling .. code-block:: python self.window.set_layout(args) or in a Key Binding using a Key-Binding dictionary like this (from the default Key Bindings), which sets up 2 side-by-side :term:`Focus Group Panels `. .. code-block:: json { "keys": ["alt+shift+2"], "command": "set_layout", "args": { "cols": [0.0, 0.5, 1.0], // 3 logical boundaries (left, mid, right), 2 "areas" for width "rows": [0.0, 1.0], // 2 logical boundaries (top, bottom), 1 "area" for height "cells": [ [0, 0, 1, 1], // one cell on left [1, 0, 2, 1] // one cell on right ] } }, Or a Command or any other method that allowed you to execute a the ``set_layout`` :term:`Command` and pass arguments. Either way, you will still be calling (directly or indirectly) the ``set_layout()`` function on the relevant ``Window`` object. ``set_layout()`` Arguments ========================== ``args`` is a 3-element dictionary object with keys "cols", "rows" and "cells". "cols" takes an array of floating-point numbers in the range of 0.0 to 1.0 that designate where vertical "logical boundaries" will go, and their relative positions within the horizontal span of the :term:`Editing Panel`. For example, in a tic-tac-toe grid (9 cells evenly spaced), there would be 4 vertical logical boundaries. Note the values passed in the "cols" array are the "X" component of the coordinates shown in the diagram below. "rows" also takes an array of floating-point numbers in the range of 0.0 to 1.0 that designate where horizontal "logical boundaries" will go, and their relative positions within the vertical span of the :term:`Editing Panel`. Using the same tic-tac-toe grid (9 cells evenly spaced), there would be 4 horizontal logical boundaries. Note the values passed in the "cols" array are the "Y" component of the coordinates shown in the diagram below. Finally, the "cells" argument is very interesting: it contains an array of integer arrays, one array for each cell, and each sub-array is the [x1, y1, x2, y2] of one cell where: - x1 = index of the "cols" logical boundary array that will be that cell's left edge - y1 = index of the "rows" logical boundary array that will be that cell's top edge - x2 = index of the "cols" logical boundary array that will be that cell's right edge - y2 = index of the "rows" logical boundary array that will be that cell's bottom edge .. code-block:: text 0 1 2 3 <-- "cols" indices for vertical 0 #===============+===============+===============# \ logical boundaries # | | # \ # | | # \ # 1 | 2 | 3 # \ # | | # \ # | | # | 1 #---------------+---------------+---------------# | # | | # | # | | # | # 4 | 5 | 6 # > Editing Panel # | | # | # | | # | 2 #---------------+---------------+---------------# | # | | # | # | | # / # 7 | 8 | 9 # / # | | # / # | | # / 3 #===============+===============+===============# / ^ ^ ^ ^ ^ | | | | | | | | | +-- 4th logical boundary | | | +-- 3rd logical boundary | | +-- 2nd logical boundary | +-- 1st logical boundary +-- "rows" indices for horizontal logical boundaries Example that accomplishes the above layout with 9 equal-sized cells: .. code-block:: json { "cols": [0.0, 0.33, 0.66, 1.0], "rows": [0.0, 0.33, 0.66, 1.0], "cells": [ [0, 0, 1, 1], // Cell 1 [1, 0, 2, 1], // Cell 2 [2, 0, 3, 1], // Cell 3 [0, 1, 1, 2], // Cell 4 [1, 1, 2, 2], // Cell 5 [2, 1, 3, 2], // Cell 6 [0, 2, 1, 3], // Cell 7 [1, 2, 2, 3], // Cell 8 [2, 2, 3, 3], // Cell 9 ], } Note that given those "cols" and "rows" arrays, there doesn't :bi:`have to be` 9 cells! You could lay out the cells like this: .. code-block:: text 0 1 2 3 <-- "cols" indices for vertical 0 #===============+===============+===============# \ logical boundaries # | | # \ # | | # \ # 1 | 2 | 3 # \ # | | # \ # | | # | 1 #---------------+---------------+---------------# | # | # | # | # | # | 5 # > Editing Panel # | # | # | # | 2 # 4 +---------------# | # | # | # | # / # | 6 # / # | # / # | # / 3 #===============+===============+===============# / ^ ^ ^ ^ ^ | | | | | | | | | +-- 4th vertical logical boundary | | | +-- 3rd vertical logical boundary | | +-- 2nd vertical logical boundary | +-- 1st vertical logical boundary +-- "rows" indices for horizontal logical boundaries with: .. code-block:: json { "cols": [0.0, 0.33, 0.66, 1.0], "rows": [0.0, 0.33, 0.66, 1.0], "cells": [ [0, 0, 1, 1], // Cell 1 [1, 0, 2, 1], // Cell 2 [2, 0, 3, 1], // Cell 3 [0, 1, 2, 3], // Cell 4 [2, 1, 3, 2], // Cell 5 [2, 2, 3, 3], // Cell 6 ], } You could use whatever proportions you wanted by changing the logical boundary-positions in the "cols" and "rows" arrays. You could lay out your :term:`Focus Group Panels ` like this: .. code-block:: text (0,0) (1,0) (2,0) (0.0)+ +-------------------------------+-------------------------------+ | | | | | | | | | | | 2 | | | | | v | (1,1) (2,1) (0.25)+ | +-------------------------------+ | | | | | | 1 | | | | | | | | | | | | | | | | | | | | | 4 | | | | | | | | | | (0,2) (1,2) | v +-------------------------------+ | (0.75)+ | | | | | | | | | 3 | | | | | | | (0,3) (1,3) (2,3) (1.0)v +-------------------------------+-------------------------------+ Using this code in a WindowCommand in a Plugin: .. code-block:: python self.window.set_layout({ "cols": [0.0, 0.5, 1.0], "rows": [0.0, 0.25, 0.75, 1.0], "cells": [ [0, 0, 1, 2], // Cell 1 [1, 0, 2, 1], // Cell 2 [0, 2, 1, 3], // Cell 3 [1, 1, 2, 3] // Cell 4 ] }) Needless to say, it is as flexible as the CSS Grid-Layout engine. Each cell will receive 1 :term:`Focus Group Panel`, each of which can display/edit multiple documents. (Remember, each sheet can also show an image or a miniHTML page as well. So the above could be a convenient layout for showing 2 images, raw HTML, and a "view" of what the HTML will look like when rendered). Keyboard Editing **************** .. TODO:: Keyboard Editing .. _spell checking: Spell Checking ============== Bracket-Type Key Behaviors ========================== Certain keys have interesting behavior when the ``auto_match_enabled`` setting is ``true``: ``'``, ``"``, ``(``, ``[``, ``{``. If you are familiar with the behavior, you can get more done with fewer keystrokes! When each caret has no text selected, hitting one of these keys causes the matching counterpart to appear to the right. If you then [Backspace], it deletes both of them... at each caret. When each caret has some text selected, hitting any of these keys wraps the selected text in the implied "brackets". See the default key bindings and search for "auto_match_enabled" to see everything they can do. (You will need to understand :ref:`key bindings context` to understand the meanings if you don't already.) This is also a good place to mention that, by default, the ``ctrl-m`` key is mapped to a command that makes the caret jump from the ``(``, ``[``, ``{`` bracket-family characters to the *opposite matching* bracket, complete with intelligence built-in for correctly interpreting nested brackets! Very useful when coding in a programming language! Find and Replace ================ Sublime |nbsp| Text features 5 different kinds of Find/Replace features, 4 of which have their own I/O Panel (like a dialog box at the bottom of the Window). These facilities offer a remarkably flexible way to find and/or replace text in the current file or recursively within a set of files under a particular directory. All the fancy find/replace features that programmers would expect of a programmable programmer's editor are available: - optional instant highlighting of found text (complete with a sky-blue marker in both gutters on the right for each match found), - optionally constraining the search to selected text, - optionally with "whole words" constraint, - optionally case-sensitive, - optionally using the full set of Perl :ref:`regular expressions` (including special modifiers) for both finding AND replacing. Plus, no matter what type of Find and/or Replace operation you are doing, you can get helpful information (e.g. about how many find results there are and which one of them is being highlighted, etc.) in the status bar. Here is a list of the Find/Replace features, with their Input Fields, options, buttons and keys involved and what they do. Where a keystroke and a button both do the same action, they are listed on the same line. - Find ``[Ctrl-F]`` (if there is a non-empty selection, that string will be copied to the Find String input panel) - Input Fields: - Find String or Regex (with history drop-down list) - Options - Regex ``[Alt-R]`` - Case Sensitive ``[Alt-C]`` - Whole Word ``[Alt-W]`` - Wrap - Within Selection - Highlight Matches - Buttons: - ``[x]``, ``[Esc]`` (Close Panel) - ``[Find]``, ``[Enter]`` or ``[F3]`` (Find Next) - ``[Find Prev]``, ``[Shift-Enter]`` or ``[Shift-F3]`` (Find Prev) - ``[Find All]`` or ``[Alt-Enter]`` (See :ref:`find all`) - Keys Not Covered Above: (none) - Incremental Find ``[Ctrl-I]`` - Input Fields: - Find String or Regex (with history drop-down list) - Options - Regex ``[Alt-R]`` - Case Sensitive ``[Alt-C]`` - Whole Word ``[Alt-W]`` - Wrap - Within Selection - Highlight Matches - Buttons: - ``[x]`` or ``[Esc]`` (Close Panel) - Keys Not Covered Above: - ``[Enter]`` or ``[F3]`` (Find Next) - ``[Shift-Enter]`` or ``[Shift-F3]`` (Find Previous) - ``[Alt-Enter]`` (See :ref:`find all`) - Replace ``[Ctrl-H]`` (if there is a non-empty selection, that string will be copied to the Find String input panel) - Input Fields: - Find String or Regex (with history drop-down list) - Replace String (with history drop-down list) (can include backreferences to Find String if it was a Regex) - Options - Regex ``[Alt-R]`` - Case Sensitive ``[Alt-C]`` - Whole Word ``[Alt-W]`` - Preserve Case ``[Alt-A]`` (applies to replace string) - Wrap - Within Selection - Highlight Matches - Buttons: - ``[x]`` or ``[Esc]`` (Close Panel) - ``[Find]``, ``[Enter]`` or ``[F3]`` - ``[Replace]`` or ``[Ctrl-Shift-H]`` - ``[Find All]`` or ``[Alt-Enter]`` (See :ref:`find all`) - ``[Replace All]`` or ``[Ctrl-Alt-Enter]`` (instantly replace all instances in current View :term:`Buffer` and close Replace Panel) - Keys Not Covered Above: - ``[Shift-Enter]`` or ``[Shift-F3]`` (Find Previous) - Find-in-Files ``[Ctrl-Shift-F]`` (if there is a non-empty selection, that string will be copied to the Find String input panel) - Input Fields: - Find String or Regex (with history drop-down list) - Where (comma-separated list of specifiers, edit with ``[...]`` button) - path to top folder to search recursively in native path format - include filters (e.g. ``*.txt``, e.g. ``C:\path\to\folder,*.txt``) - exclude filters (like include filters but prefixed with a hyphen) - ```` (meaning these optional lists from within the currently-open project along with their meanings: - "path": "C:\path\to\project\root" - "file_exclude_patterns": [file_spec_list] - "folder_exclude_patterns": [file_spec_list] - ```` (only those folders open within the current project) - ```` (only those files already open in a View) - ```` (only current file) - Replace String (with history drop-down list) (can include backreferences to Find String if it was a Regex) - Options - Regex ``[Alt-R]`` - Case Sensitive ``[Alt-C]`` - Whole Word ``[Alt-W]`` - Use .gitignore (applies to Where string) - Preserve Case ``[Alt-A]`` (applies to Replace string) - Buttons: - ``[x]`` or ``[Esc]`` (Close Panel) - ``[Find]`` or ``[Enter]`` (recursively searches "Where" specification appending results to "Find Results" View, creating one if it doesn't already exist) - ``[...]`` next to "Where" Input Panel, partially automates editing of "Where" specification. - ``[Replace]`` or ``[Ctrl-Alt-Enter]`` (pops up a dialog box with confirmation message like "Find 25 occurrences across 10 files" with ``[Replace]`` and ``[Cancel]`` buttons; ``[Esc]`` closes dialog box) - Keys Not Covered Above: - ``[F3]`` (Finds Next in current View) - ``[Shift-F3]`` (Find Previous in current View) - The direct ``Find All`` operation does not have its own panel. See :ref:`find all` for details. .. _find all: Power Feature: Find All ------------------------ The plain "Find" Overlay Panel (Ctrl+F by default) does all the usual things, and accomplishes finding in the current View (one single file at a time). But there is something very powerful and "Sublime-ish" that is worth mentioning: clicking the ``[Find All]`` button literally places a selection with the caret on the right side of each selection. If you know about this and take advantage of it, it can make some complex editing tasks a breeze. While each match is selected, the following keystrokes perform special actions: - ``[Esc]`` exits Find-All Mode, reverting to a single selection. - ``[<-]`` or ``[->]`` arrow key de-selects each instance placing the caret on the left or right side of each match string respectively, turning all selections into carets. - ``[Del]`` or ``[Backspace]`` deletes each instance, turning all selections into carets. - Any printable key, ``[Enter]``, or pasting from the clipboard replaces all selections with the entered keystroke or text (`\n` for ``[Enter]`` key), turning all selections into carets. Example: You are editing a list of words (e.g. a plain-text dictionary list) that has no line endings in it, so the long list extends out 4, 8 or 16KB to the right all on line line, and you want to work with it as a vertical list list with one word on each line. And let's say you don't know if any words might have multiple spaces and/or tabs between them. Using the Regular Expressions feature (you can toggle it ON and OFF using Alt-R while keyboard focus is in the Find :term:`Overlay Panel`), you can search for something like ``\s+`` to find all the white space and then click ``[Find All]``, and all of a sudden, you are in the very powerful position of being able to type any printable character (including ``[Enter]``) to replace the found text at EVERY location where it was found! Hit the ``[Enter]`` key, and voilà—you are now looking at the vertical list you wanted to create! And how many keystrokes did that take? Let's count them: - ``[Ctrl-F]`` (to open and place keyboard focus on the Find Overlay Panel) - ``[Alt-R]`` (to turn on Regular Expression mode, if it wasn't already turned on from a previous find operation) - \\s+ - ``[Alt-Enter]`` (or click the ``[Find All]`` button, which interestingly places keyboard focus back in the editing area again) - ``[Enter]`` Remarkable! The reverse can be done just as easily! With your vertical list, now try this: - ``[Ctrl-F]`` (note that the Find Panel remains how you left it; note that ``\s+`` also matches ``\n`` [newline] characters) - ``[Alt-Enter]`` (or click ``[Find All]``) - ``[Backspace]`` - ``[Space]`` Voilà—all the words are now back on line line again! Simultaneously, you *also know* that exactly 1 space now separates each word. That same type of operation can be limited to a block of selected text by toggling the "In Selection" mode button (4 buttons to the right of the Regular Expression Mode button). Once you've seen how easy that is, you can extrapolate to discover other things you can do with this powerful feature. Find All from Selection ~~~~~~~~~~~~~~~~~~~~~~~ Alternately, you can select a term you want to find and hit ``[Alt-F3]`` to instantly have all instances of that string selected with the caret on the right side of each selection. (This replaces 6 keystrokes from the ``[Ctrl-F]`` version of Find All.) .. _regular expressions: Regular Expressions ------------------- If you are not already acquainted with Regular Expressions, now is a good time to learn them because they provide a very powerful way of finding and replacing text that can save a great deal of editing time when you know what you are doing. **Recommended References for Regular Expressions:** - `Perl Regular Expression Tutorial `__ (an excellent way to learn Regular Expressions from the ground up [hint: study this in sequence]) - `Perl Regular Expressions Quick Start `__ (a considerably shorter version of the Tutorial for programmers) - `The Definitive Perl Regular Expression Reference `__ (explains EVERYTHING [sometimes more than you need] and is very well written) - `Perl Regular Expression Cheat Sheet `__ (excellent way to "brush up" once you have already studied and practiced everything) **Additional References (Which May or May Not Be for Beginners):** - `Mozilla's Web Development JavaScript Regular Expression Reference `__ (and all its subordinate pages; this documentation has great cross-references in "See Also" sections at the bottom of each page) - `RegexBuddy's Regex Reference Website `__ which encompasses all "flavors" of Regular Expressions (not just Perl regexes). .. note:: While Sublime |nbsp| Text uses the C++ Boost library's Regular Expression subsystem, which itself is based on the Perl Regular Expression engine, this author does not like to refer others to its documentation at this time (~30-May-2025) because it is quite poor in that it uses terms that it does not define, and is a great way to get very confused. .. _find in files: Find in Files, a.k.a. Recursive File Searching ---------------------------------------------- For file searching while doing a recursive "directory walk", filters of various kinds can be applied to include or exclude specified folders or file types using the ``[...]`` button. In the Find-in-Files operation with the ``[Find]`` button (or hitting ``[Enter]``), Sublime |nbsp| Text outputs what it found into a "Find Results" :term:`View`, which itself can be edited, have its sections folded (one per file), and saved to a text file of your choosing via ``File > Save As...`` if you need to keep the contents for any reason. This "Find Results" View comes with with a configurable amount of context ``[surrounding lines]`` at each point where a match was found. In this View, each instance of the found string (or regex) is highlighted. If you double-click on the line containing any of these highlights, Sublime |nbsp| Text will open the relevant file(if it isn't already opened) and place your cursor on the line where the match was found. If you use the "Find Results" list as a checklist, for example, in manually editing certain files in your project, you can either code-fold or delete the parts of the list which you have already handled. This is remarkably convenient for making sure you don't miss anything, and you won't be prompted to save the file when you close the View. Over and above that, if you leave the "Find Results" View open, it is a great way to accumulate Find Results if you need to, because each subsequent Find-in-Files ``[Find]`` operation appends its results to the end of the existing "Find Results" View in a well-labelled manner. Such an accumulated list might serve as a checklist for a task later on. While the "Find Results" View is open, the "Next Result" and "Previous Result" commands can be applied (mapped to the ``[F4]`` and ``[Shift+F4]`` keys respectively, by default). Using these commands opens the applicable file and places your cursor on the applicable line, in the sequence they appear in the "Find Results" View. Find-in-Files Replace Operation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you click the ``[Replace]`` button in the Find-in-Files Panel, you will get a confirmation dialog box that says something like: "Replace 2 occurrences across 2 files?" with a ``[Replace]`` and ``[Cancel]`` button. If you click ``[Replace]``, then the occurrences found will be replaced, and the Views showing those files will be left open and unsaved for you to view and confirm the changes before the Views overwrite their counterparts on disk. If you haven't mapped the ``save_all`` command to a :term:`Key Binding` yet, when you feel it is safe to do so, you can save all the unsaved files at once using ``File > Save All``. Leaving the Find Panel Open --------------------------- Leaving the Find Panel open also causes found-string highlighting in the editing area to remain active. This can be helpful if you are using the highlighted text to make certain things more visible while you are editing. This can also be useful if you need to make a different type of edit at each location where that string is found. After the Find Panel Has Closed ------------------------------- After the Find Panel has closed, the "Find string" is still silently active, but the highlighting isn't. However, any time you hit ``[F3]`` or ``[Shift+F3]``, it will do a Find-Next or Find-Previous operation from your current cursor location. Macros ====== .. TODO:: write Macros section Further Reading =============== See :ref:`key bindings` to see how Sublime Edit's various Ctrl+, Alt-, and Shifted key combinations are mapped for virtually *all* of Sublime |nbsp| Text's key-based navigation and editing operations. See also: - ``Default ($platform).sublime-keymap`` (via ``Preferences > Key Bindings``) - https://docs.sublimetext.io/guide/usage/editing.html . Mouse Features ************** Sublime |nbsp| Text implements the normal mouse features found in any editor, but additionally makes possible some clever additions that dovetail with Sublime |nbsp| Text's ability to have more than one cursor active in a given View. .. TODO:: Mouse Features details. See also Default ($platform).sublime-mousemap