mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-21 21:58:00 +01:00
311 lines
9.0 KiB
JavaScript
311 lines
9.0 KiB
JavaScript
/***** BEGIN LICENSE BLOCK ***** {{{
|
|
*
|
|
* Mozilla Public License Notice
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License
|
|
* at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS"
|
|
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
|
* the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
}}} ***** END LICENSE BLOCK *****/
|
|
|
|
// command names taken from:
|
|
// http://developer.mozilla.org/en/docs/Editor_Embedding_Guide
|
|
|
|
function Editor() //{{{
|
|
{
|
|
// store our last search with f,F,t or T
|
|
var last_findChar = null;
|
|
var last_findChar_func = null;
|
|
|
|
function editor()
|
|
{
|
|
return window.document.commandDispatcher.focusedElement;
|
|
}
|
|
|
|
function getController()
|
|
{
|
|
var el = window.document.commandDispatcher.focusedElement;
|
|
if (!el || !el.controllers)
|
|
return null;
|
|
|
|
return el.controllers.getControllerAt(0);
|
|
}
|
|
|
|
this.line = function()
|
|
{
|
|
var line = 1;
|
|
var text = editor().value;
|
|
for (var i = 0; i < editor().selectionStart; i++)
|
|
if (text[i] == "\n")
|
|
line++;
|
|
return line;
|
|
}
|
|
|
|
this.col = function()
|
|
{
|
|
var col = 1;
|
|
var text = editor().value;
|
|
for (var i = 0; i < editor().selectionStart; i++)
|
|
{
|
|
col++;
|
|
if (text[i] == "\n")
|
|
col = 1;
|
|
}
|
|
return col;
|
|
}
|
|
|
|
this.unselectText = function()
|
|
{
|
|
var elt = window.document.commandDispatcher.focusedElement;
|
|
if (elt && elt.selectionEnd)
|
|
elt.selectionEnd = elt.selectionStart;
|
|
}
|
|
|
|
this.selectedText = function()
|
|
{
|
|
var text = editor().value;
|
|
return text.substring(editor().selectionStart, editor().selectionEnd);
|
|
}
|
|
|
|
this.pasteClipboard = function()
|
|
{
|
|
var elt = window.document.commandDispatcher.focusedElement;
|
|
|
|
if (elt.setSelectionRange && readFromClipboard())
|
|
// readFromClipboard would return 'undefined' if not checked
|
|
// dunno about .setSelectionRange
|
|
{
|
|
var rangeStart = elt.selectionStart; // caret position
|
|
var rangeEnd = elt.selectionEnd;
|
|
var tempStr1 = elt.value.substring(0,rangeStart);
|
|
var tempStr2 = readFromClipboard();
|
|
var tempStr3 = elt.value.substring(rangeEnd);
|
|
elt.value = tempStr1 + tempStr2 + tempStr3;
|
|
elt.selectionStart = rangeStart + tempStr2.length;
|
|
elt.selectionEnd = elt.selectionStart;
|
|
}
|
|
}
|
|
|
|
// count is optional, defaults to 1
|
|
this.executeCommand = function(cmd, count)
|
|
{
|
|
var controller = getController();
|
|
var el = window.document.commandDispatcher.focusedElement;
|
|
if (!controller || !el)
|
|
return false;
|
|
|
|
if (!controller.supportsCommand(cmd) || !controller.isCommandEnabled(cmd))
|
|
{
|
|
vimperator.beep();
|
|
return false;
|
|
}
|
|
|
|
if (typeof count != "number" || count < 1)
|
|
count = 1;
|
|
|
|
var did_command = false;
|
|
while(count--)
|
|
{
|
|
// some commands need this try/catch workaround, because a cmd_charPrevious triggered
|
|
// at the beginning of the textarea, would hang the doCommand()
|
|
// good thing is, we need this code anyway for proper beeping
|
|
try
|
|
{
|
|
controller.doCommand(cmd);
|
|
did_command = true;
|
|
}
|
|
catch(e)
|
|
{
|
|
if (!did_command)
|
|
vimperator.beep();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// cmd = y, d, c
|
|
// motion = b, 0, gg, G, etc.
|
|
this.executeCommandWithMotion = function(cmd, motion, count)
|
|
{
|
|
if (!typeof count == "number" || count < 1)
|
|
count = 1;
|
|
|
|
if (cmd == motion)
|
|
{
|
|
motion = "j";
|
|
count--;
|
|
}
|
|
|
|
vimperator.modes.set(vimperator.modes.VISUAL, vimperator.modes.TEXTAREA);
|
|
|
|
switch (motion)
|
|
{
|
|
case "j":
|
|
this.executeCommand("cmd_beginLine", 1);
|
|
this.executeCommand("cmd_selectLineNext", count+1);
|
|
break;
|
|
case "k":
|
|
this.executeCommand("cmd_beginLine", 1);
|
|
this.executeCommand("cmd_lineNext", 1);
|
|
this.executeCommand("cmd_selectLinePrevious", count+1);
|
|
break;
|
|
case "h":
|
|
this.executeCommand("cmd_selectCharPrevious", count);
|
|
break;
|
|
case "l":
|
|
this.executeCommand("cmd_selectCharNext", count);
|
|
break;
|
|
case "e":
|
|
case "w":
|
|
this.executeCommand("cmd_selectWordNext", count);
|
|
break;
|
|
case "b":
|
|
this.executeCommand("cmd_selectWordPrevious", count);
|
|
break;
|
|
case "0":
|
|
case "^":
|
|
this.executeCommand("cmd_selectBeginLine", 1);
|
|
break;
|
|
case "$":
|
|
this.executeCommand("cmd_selectEndLine", 1);
|
|
break;
|
|
case "gg":
|
|
this.executeCommand("cmd_endLine", 1);
|
|
this.executeCommand("cmd_selectTop", 1);
|
|
this.executeCommand("cmd_selectBeginLine", 1);
|
|
break;
|
|
case "G":
|
|
this.executeCommand("cmd_beginLine", 1);
|
|
this.executeCommand("cmd_selectBottom", 1);
|
|
this.executeCommand("cmd_selectEndLine", 1);
|
|
break;
|
|
|
|
default:
|
|
vimperator.beep();
|
|
return false;
|
|
}
|
|
|
|
switch (cmd)
|
|
{
|
|
case "d":
|
|
this.executeCommand("cmd_delete", 1);
|
|
// need to reset the mode as the visual selection changes it
|
|
vimperator.modes.main = vimperator.modes.TEXTAREA;
|
|
break;
|
|
case "c":
|
|
this.executeCommand("cmd_delete", 1);
|
|
vimperator.modes.set(vimperator.modes.INSERT, vimperator.modes.TEXTAREA);
|
|
break;
|
|
case "y":
|
|
this.executeCommand("cmd_copy", 1);
|
|
this.unselectText();
|
|
break;
|
|
|
|
default:
|
|
vimperator.beep();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// This function will move/select up to given "pos"
|
|
// Simple setSelectionRange() would be better, but we want to maintain the correct
|
|
// order of selectionStart/End (a firefox bug always makes selectionStart <= selectionEnd)
|
|
// Use only for small movements!
|
|
this.moveToPosition = function(pos, forward, select)
|
|
{
|
|
if (!select)
|
|
{
|
|
editor().setSelectionRange(pos, pos);
|
|
return;
|
|
}
|
|
|
|
if (forward)
|
|
{
|
|
if (pos <= editor().selectionEnd || pos > editor().value.length)
|
|
return false;
|
|
|
|
do // TODO: test code for endless loops
|
|
{
|
|
this.executeCommand("cmd_selectCharNext", 1);
|
|
}
|
|
while ( editor().selectionEnd != pos );
|
|
}
|
|
else
|
|
{
|
|
if (pos >= editor().selectionStart || pos < 0)
|
|
return false;
|
|
|
|
do // TODO: test code for endless loops
|
|
{
|
|
this.executeCommand("cmd_selectCharPrevious", 1);
|
|
}
|
|
while ( editor().selectionStart != pos );
|
|
}
|
|
}
|
|
|
|
// returns the position of char
|
|
this.findCharForward = function(char, count)
|
|
{
|
|
if (!editor())
|
|
return -1;
|
|
|
|
last_findChar = char;
|
|
last_findChar_func = this.findCharForward;
|
|
|
|
var text = editor().value;
|
|
if (!typeof count == "number" || count < 1)
|
|
count = 1;
|
|
|
|
for (var i = editor().selectionEnd + 1; i < text.length; i++)
|
|
{
|
|
if (text[i] == "\n")
|
|
break;
|
|
if (text[i] == char)
|
|
count--;
|
|
if (count == 0)
|
|
return i + 1; // always position the cursor after the char
|
|
}
|
|
|
|
vimperator.beep();
|
|
return -1;
|
|
}
|
|
// returns the position of char
|
|
this.findCharBackward = function(char, count)
|
|
{
|
|
if (!editor())
|
|
return -1;
|
|
|
|
last_findChar = char;
|
|
last_findChar_func = this.findCharBackward;
|
|
|
|
var text = editor().value;
|
|
if (!typeof count == "number" || count < 1)
|
|
count = 1;
|
|
|
|
for (var i = editor().selectionStart - 1; i >= 0; i--)
|
|
{
|
|
if (text[i] == "\n")
|
|
break;
|
|
if (text[i] == char)
|
|
count--;
|
|
if (count == 0)
|
|
return i;
|
|
}
|
|
|
|
vimperator.beep();
|
|
return -1;
|
|
}
|
|
|
|
} //}}}
|
|
|
|
// vim: set fdm=marker sw=4 ts=4 et:
|