<type>documentation</type>
<domain>scripting</domain>
<id>editor</id>
<title>API Reference - Editor</title>
<product>per+</product>


API support for the editor has two parts:

**(1)** ``CAPIDocument`` is used to access the buffer that contains the text for one or
more editors. Multiple editors may share a single buffer, and buffers are also used for
search or source analysis operations.

**(2)** ``CAPIEditor`` is used to access a single editor in the user interface, with a
single file open in it. Each editor tab in Wing is a separate editor.


Class CAPIDocument
==================

API to access an open editor document. This class should not be instantiated
directly. Use the methods on ``CAPIApplication`` and ``CAPIEditor`` instead.

A single document may be shared by multiple open editors, and/or search and
static code analysis tasks.
  
The document uses an internal utf-8 encoded buffer and positions returned from
methods or used as arguments are positions in that utf-8 buffer.  However, text
is returned as a str instance, which is not utf-8 encoded just like all other
Python 3 str instances.  Because of this, the len() of the str instances
returned may not be equal to the len() of the internal utf-8 buffer.

**Signals**

A callback can be connected to the following signals using ``Connect(signal, cb)``:
    
  ``destroy``: The document is closing.  Calls cb(doc:CAPIDocument).
  
  ``modified``: The document's text has been modified. Calls ``cb(insert:bool,
  pos:int, length:int, text:str, lines_added:int)`` where:
  
    ``insert`` is ``True`` if text was inserted and ``False`` if text was deleted.
    
    ``pos`` is the position of the change.
    
    ``length`` is the length of text affected.
    
    ``text`` is the text that was inserted or deleted.
    
    ``lines_added`` is the number of lines added.
    
  ``presave``: The document is about to be saved to disk. Calls ``cb(filename:str,
  encoding:str)`` where ``filename`` and ``encoding`` are ``None`` if the
  document-specified location and encoding will be used. The callback may make changes
  to the buffer if desired, though this is best avoided if ``filename`` is not ``None``.
                     
  ``save-point``: The document has entered or left a save point, where it matches the
  copy that was read from or written to disk. Calls ``cb(save_point:bool)`` where
  ``save_point`` is True if a save point was reached and ``False`` if leaving the save
  point.
                     
  ``filename-changed``: The filename for this document has changed. Calls
  ``cb(old_name:str, new_name:str)`` where ``old_name`` and ``new_name`` are full
  paths.

Use ``Disconnect(signal_id)`` to preemptively disconnect a signal handler, where
``signal_id`` is the signal ID previously returned from ``Connect``.


General Access
==============

**CAPIDocument.GetMimeType()**

Get the mime type for this document, as determined by file name, contents, and
`Files > File Types > Extra File Types
<script:show_preferences_gui#prefname="main.extra-mime-types">`__ preference.

**CAPIDocument.GetFilename()**

Get the file name this document. For untitled or scratch buffers, the file name is
prefixed with ``unknown:``. For remote files, the file name will be a URL. Use
``IsUrl`` to distinguish between file names and URLs.

**CAPIDocument.GetEditors()**

Get all existing editors for this document.  This may be an empty list if the
document is only open for searching or static analysis.


Buffer Access
=============

**CAPIDocument.GetText()**

Get the document's contents as a string

**CAPIDocument.SetText(txt)**

Set the document contents, replacing any existing content.  The ``txt`` must be
either a unicode string or utf-8 encoded text.

**CAPIDocument.DeleteChars(start, end)**

Delete characters in given range, including the character starting at the ``end`` offset.
The offsets are utf-8 offsets.

**CAPIDocument.InsertChars(pos, txt)**

Insert characters at the given position. The ``txt`` must either be an
unicode string or utf-8 encoded bytes instance. The pos is the offset in
the internal utf-8 encoded buffer.

**CAPIDocument.GetLength()**

Get the total length of document's utf-8 buffer.

**CAPIDocument.GetLineCount()**

Get the total number of lines in the document.

**CAPIDocument.GetCharRange(start, end)**

Get the text in the given range as a string. The offsets are relative
to the utf-8 encoded buffer.  Note that the string returned will be a str
instance and its len() may not equal end - start 

**CAPIDocument.GetLineNumberFromPosition(pos)**

Get the line number (0=first) at the given position in the utf-8 encoded buffer

**CAPIDocument.GetLineStart(lineno)**

Get the character position for the start of the given line number (0=first). The
offset is relative to the utf-8 encoded buffer.

**CAPIDocument.GetLineEnd(lineno)**

Get the character position for the end of given line number (0=first). The offset
is relative to the utf-8 encoded buffer.

**CAPIDocument.GetAsFileObject()**

Get the document's contents in a file-like object with read() and readline()
methods. Both methods return str instances 


Undo/Redo
=========

**CAPIDocument.BeginUndoAction()**

Mark the start of an undoable action group. All edits between this call and
``EndUndoAction`` will be undone in a single ``undo`` operation.

It is critical to call ``EndUndoAction`` at the end of the action or the user will
experience undos that span many more edits than intended. Use try/finally to guarantee
this a follows:

.. python::

  doc.BeginUndoAction()
  try:
    # edits here
  finally:
    doc.EndUndoAction()

**CAPIDocument.EndUndoAction()**

Mark the end of an undoable action group.

**CAPIDocument.CanUndo()**

Check whether undo is available.

**CAPIDocument.CanRedo()**

Check whether redo is available.

**CAPIDocument.Undo()**

Undo one edit action in the document.

**CAPIDocument.Redo()**

Redo edits previously undone with ``Undo``.


Saving
======

**CAPIDocument.Save(filename=None)**

Save the document to disk. If a file name is given, a copy is saved there without
altering the document's primary file.

**CAPIDocument.IsSavePoint()**

Check whether the buffer matches its file on disk.  Returns ``True`` if it does.


Class CAPIEditor
================

API to access an editor.  This class should not be instantiated directly.
Use the methods on ``CAPIApplication`` instead.

**Signals**

A callback can be connected to the following signals using ``Connect(signal, cb)``:
          
  ``destroy``: The editor has been destroyed.  Calls ``cb(editor:CAPIEditor)``.
  
  ``selection-changed``: The current selection has changed. Calls ``cb(start:int,
  end:int)`` with the new selection, relative to the utf-8 contents of the
  ``CAPIDocument``.
  
  ``selection-lines-changed``: The starting and/or ending line for the selection has
  changed. In Python files this is *not* emitted when the selection moves to a new
  physical line within the same logical line of code. Calls ``cb(first_line,
  last_line)`` with the new first and last lines (0=first line in file).
                             
  ``scrolled``: The editor view has scrolled. Calls ``cb(top_line)`` with the new first
  visible line (0=first line in file).
                             
  ``visible-lines-changed``: The range of visible lines has changed. Calls cb(top_line,
  ``bottom_line)`` with the new top and bottom lines (0=first line in file).
                             
  ``readonly-edit-attempt``: An edit was attempted and rejected on a readonly file.
  ``Calls cb()`` without arguments.
                             
  ``data-entry-stopped``: Data entry mode has stopped. Calls ``cb(data_entry_id)`` where
  ``data_entry_id`` is the ID returned from ``StartDataEntry``.
    
Use ``Disconnect(signal_id)`` to preemptively disconnect a signal handler, where
``signal_id`` is the signal ID previously returned from ``Connect``.


General Access
==============

**CAPIEditor.IsReadOnly()**

Check whether the editor is readonly.  Returns ``True`` or ``False``.

**CAPIEditor.SetReadOnly(readonly)**

Set whether or not the editor is read-only.  ``readonly`` should be ``True``
or ``False``.

**CAPIEditor.GetDocument()**

Get the ``CAPIDocument`` object being shown in this view.


Selections
==========

**CAPIEditor.GetSelection()**

Get ``(start, end)`` for the selection on the editor. ``start`` is always less
than ``end``. The offsets are relative to the utf-8 encoded text in the editor's
``CAPIDocument``.

**CAPIEditor.GetSelectedDottedName()**

Get ``(dotted_name, lineno)`` for the current selection on the editor.  The
dotted_name may be a simple symbol like 'text', an expression like
'modname.classname.attrib', or None if no dotted name is found at the current
selection position.

**CAPIEditor.GetAnchorAndCaret()**

Get the current selection anchor and caret position.  The anchor may come after
the caret position if the user has selected backwards in the text.  The offsets are
relative to the utf-8 encoded text in the editor's ``CAPIDocument``.

**CAPIEditor.SetSelection(start, end, expand=1)**

Set the selection on the editor, optionally expanding any folded parts to show the
selection. ``start`` is the selection anchor and ``end`` is the caret position. The
anchor can be before or after the caret. Does not alter scroll position. Offsets are
relative to the utf-8 encoded text in the editor's ``CAPIDocument``.

**CAPIEditor.GetClickLocation()**

Get the offset in the utf-8 encoded text buffer for the last mouse click on the
editor.

**CAPIEditor.GetSourceScope()**

Get the current source scope, based on position of selection or insertion caret.

Returns ``None`` if nothing is selected or a list that contains a filename, a line
number (0=first), and zero or more source symbol names indicating the nested scope
that the user has selected.

For example:

.. python::

  ["/x/y/z.py", 120, "Class1", "Method1"]
  
For untitled or scratch buffers, the file name is prefixed with ``unknown:``. For
remote files, the file name will be a URL. Use ``IsUrl`` to distinguish between file
names and URLs.


Scrolling and Visual State
==========================

**CAPIEditor.GetFirstVisibleLine()**

Get the line number of the first visible line (0=first in file) on screen in this
editor.

**CAPIEditor.GetNumberOfVisibleLines()**

Get the number of visible lines on screen for this editor.

**CAPIEditor.ScrollToLine(lineno, select=0, pos='slop', store_history=1, callout=0)**

Scroll so that given line (0=first) or selection is visible in the editor.

``select`` can be one of:

  ``0`` to make no changes in selection.
  
  ``1`` to select the whole line.
  
  ``2`` to place the caret at the start of the line.
  
  ``(start, end)`` to select the given character range, relative to the utf-8
  buffer for the editor.  In this case, ``lineno`` may be set to ``-1`` to
  compute the line number from the selection.

``pos`` can be one of:

  ``slop`` to ensure visibility without a specific position.
  
  ``center`` to always center the line on the display.
  
  ``top`` to always position the line at the top of the display.
  
  Only ``center`` and ``top`` will work if the editor has not yet been shown.
    
Set ``store_history`` to ``False`` to avoid remembering the current editor position in
the visit history.

Set ``callout`` to ``True`` to briefly display a callout to highlight the
given text selection.

**CAPIEditor.GetVisualState(errs=[], style='all')**

Get the current visual state of the editor, including scroll position, selection,
and so forth.

The ``style`` of the state may be one of:

  'all' to capture all of the application visual state
  
  'tools-and-editors' to capture which tools are visible, the overall layout of the
  windows, and which editors are open (but not details like scroll positions,
  selection, or current search string)
  
  'tools-only' to capture only which tools are visible and the overall layout of the
  windows (but not which editors are open).

Returns an opaque dictionary with the state, for later use with ``SetVisualState``.

Any errors encountered are added to ``errs`` as strings.

**CAPIEditor.SetVisualState(state)**

Restore a visual state previously obtained with ``GetVisualState``.


Folding
=======

**CAPIEditor.FoldingAvailable()**

Check whether folding is available and enabled on this editor.

**CAPIEditor.FoldUnfold(fold_check_cb)**

Folds or unfolds all the fold points, as determined by the given call back, which
is called with (line_text, line_number) where line_number 0=first. The callback should
return 1 to expand, 0 to collapse, and -1 to leave a fold point untouched. If the
callback is not a callable, all the folds are either expanded or collapsed according
to the value of ``bool(fold_check_cb)``.

Returns a list of lineno's that were folded and a list of line numbers (0=first) that
were expanded.


Indentation
===========

**CAPIEditor.GetTabSize()**

Get the effective tab size for this editor, as determined by the contents of the
file and indentation preferences.

**CAPIEditor.GetIndentSize()**

Get the indent size for this editor, as determined by the contents of the file and
indentation preferences.

**CAPIEditor.GetIndentStyle()**

Get the predominant indent style used in this file.  Returns one of::
1 -- spaces only
2 -- tabs only
3 -- mixed tabs and spaces

**CAPIEditor.SetIndentStyle(style)**

Set the indent style to use in this editor. This should only be used on an empty
file or to force indent style regardless of existing file content (not a good idea
with Python files).

**CAPIEditor.GetEol()**

Get one end-of-line that matches the content of this editor. Returns one of:
``"\n"``, ``"\r"``, or ``"\r\n"``.


Command Execution

These methods execute editor commands documented in the ``Active Editor Commands``
section of the `Editor Commands <ref:commands/edit>`__ reference."""

**CAPIEditor.CommandAvailable(cmd_name, **args)**

Check the whether an editor command is available for execution with the given
arguments. Arguments may be omitted if they don't affect command availability, which
most don't.

The available commands for an editor are documented in the ``Active Editor Commands``
section of the `Editor Commands <ref:commands/edit>`__ reference.

**CAPIEditor.ExecuteCommand(cmd_name, **args)**

Execute the given command in the editor. Any command arguments are passed on the
command line via ``args``.  This is used to execute commands in an editor even if
it does not have focus.

The available commands for an editor are documented in the ``Active Editor Commands``
section of the `Editor Commands <ref:commands/edit>`__ reference.


Snippets and Data Entry mode
============================


**Class CAPIEditor.CAPIFieldMetaData**

Stores meta data for fields used with the ``meta_data`` argument for
``StartDataEntry`` and ``PasteSnippet``, in order to control how fields
are filled and visited.

Available keywords arguments for the constructor are:

  ``auto_enter_from`` specifies the field index (0=first) from which data for this
  field should be auto-entered, rather than allowing the user to type into the field.
  This is used for fields that appear several times. Default: ``-1``, which indicates
  no auto-entering for the field.
    
  ``force_tab_stop`` may be set to ``True`` to force including the field as a tab stop
  even if it is auto-entered from another field. This allows the user to change the
  auto-entered value. Default: ``False``
    
  ``skip_tab_stop`` is set to ``True`` to skip this field when traversing fields. This
  is useful for placing a marker that is tracked during editing but not visited as a
  tab stop. Default: ``False``

For example to auto-enter a value from field ``3``:

.. python::

  meta = CAPIFieldMetaData(auto_enter_from=3, force_tab_stop=True)
  

**CAPIEditor.PasteSnippet(txt, fields, auto_terminate=False, meta_data={})**

Paste a utf-8 text snippet into the editor and place the editor into inline data
entry mode. Snippet syntax is documented in `Snippet Syntax
<ref:edit/snippet-syntax>`__.

The ``txt`` is the text to paste.

``fields`` provides the ``(start, end)`` offsets within that text for fields the user
can enter or alter.

Set ``auto_terminate`` to stop data entry mode when the last field is reached.

To control behavior of the fields, set ``meta_data`` to a dictionary from field index
(0=first) to ``CAPIEditor._CAPIFieldMetaData``.

**CAPIEditor.StartDataEntry(fields, active_range=(0, -1), goto_first=True, auto_terminate=False, meta_data={})**

Start inline data entry mode so the user can use the ``Tab`` and ``Shift-Tab`` keys
to move between data fields inline in the editor.

``fields`` is a list of ``(start, end)`` positions where the fields are located,
in tab traversal order.

``active_range`` indicates the range of text within which the data mode will exist.
Data entry terminates if the caret moves outside of this range or if the user presses
``Esc``. The default range of ``(0, -1)`` indicates the entire document.

When ``goto_first`` is set, the first field in the tab sequence will become the
current selection.

Set ``auto_terminate`` to stop data entry mode when the last field is reached.

To control behavior of the fields, set ``meta_data`` to a dictionary from field index
(0=first) to ``CAPIEditor._CAPIFieldMetaData``.

Returns ``None`` if data entry failed to start or otherwise a unique ID for the data
entry action.

This may be invoked recursively so that another data entry action is used to fill in a
field of a previously created data entry action.

**CAPIEditor.StopDataEntry()**

Exit inline data entry mode.  If ``StartDataEntry`` was recursively invoked
then the innermost data entry action is exited.

**CAPIEditor.ActiveDataEntry()**

Get the id of the active data entry action, or ``None`` if there is none.


Utilities
=========

**CAPIEditor.GrabFocus()**

Set keyboard focus on this editor.

**CAPIEditor.SendKeys(keys)**

Send a string of one or more keys to the editor so they are processed as if they
were typed by the user. Key processing includes any auto-editing, auto-indentation,
etc.

