8000 [DO NOT PULL] Issue #7 Selection and Copy by Eugene-msc · Pull Request #389 · p-e-w/finalterm · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
This repository was archived by the owner on Nov 11, 2018. It is now read-only.

[DO NOT PULL] Issue #7 Selection and Copy #389

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ vala_precompile(VALA_C
src/Command.vala
src/Settings.vala
src/Metrics.vala
src/Selection.vala
PACKAGES
${PKGS}
posix
Expand Down
13 changes: 7 additions & 6 deletions data/KeyBindings/default.ftkeys
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ F11 = TOGGLE_FULLSCREEN
KP_Delete = SEND_TO_SHELL "\\033[3~"
Delete = SEND_TO_SHELL "\\033[3~"
# TODO: Copy *selection* to clipboard
#<Ctrl>Insert = COPY_TO_CLIPBOARD
#<Ctrl><Shift>C = COPY_TO_CLIPBOARD

<Ctrl>Insert = COPY_TO_CLIPBOARD
<Ctrl><Shift>C = COPY_TO_CLIPBOARD
<Shift>Insert = PASTE_FROM_CLIPBOARD
<Ctrl><Shift>V = PASTE_FROM_CLIPBOARD

Expand Down Expand Up @@ -136,10 +137,10 @@ Right { cursor } = SEND_TO_SHELL "\\033OC"
<Mod1>Return { crlf } = SEND_TO_SHELL "\\033\\r\\n"
Return { ~crlf } = SEND_TO_SHELL "\\r"
Return { crlf } = SEND_TO_SHELL "\\r\\n"
<Shift>Insert { ~keypad } = SEND_TO_SHELL "\\033[4l"
<Shift>Insert { keypad } = SEND_TO_SHELL "\\033[2\;2~"
<Ctrl>Insert { ~keypad } = SEND_TO_SHELL "\\033[L"
<Ctrl>Insert { keypad } = SEND_TO_SHELL "\\033[2\;5~"
#<Shift>Insert { ~keypad } = SEND_TO_SHELL "\\033[4l"
#<Shift>Insert { keypad } = SEND_TO_SHELL "\\033[2\;2~"
#<Ctrl>Insert { ~keypad } = SEND_TO_SHELL "\\033[L"
#<Ctrl>Insert { keypad } = SEND_TO_SHELL "\\033[2\;5~"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do these lines have to be commented? The "Shift+Insert" shortcut works on my system even with these lines enabled – it's the "Ctrl+Shift+V" shortcut I can't get to work.

Insert { ~keypad } = SEND_TO_SHELL "\\033[4h"
Insert { keypad } = SEND_TO_SHELL "\\033[2~"
<Ctrl>Delete { ~keypad } = SEND_TO_SHELL "\\033[M"
Expand Down
10 changes: 7 additions & 3 deletions src/FinalTerm.vala
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,13 @@ public class FinalTerm : Gtk.Application {
return;

case Command.CommandType.COPY_TO_CLIPBOARD:
if (command.parameters.is_empty)
return;
Utilities.set_clipboard_text(command.parameters.get(0));
string text = active_terminal_widget.get_selected_text();
if (text == "") {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem here is that if any text is selected, clicking a "copy to clipboard" entry in a semantic text menu (e.g. for an IP address) will copy the selection rather than the text menu caption, which is not what the user expects. A separate COPY_SELECTION_TO_CLIPBOARD command is probably needed.

text = command.parameters.get(0);
}
if (text != "") {
Utilities.set_clipboard_text(text);
}
return;

case Command.CommandType.PASTE_FROM_CLIPBOARD:
Expand Down
122 changes: 119 additions & 3 deletions src/LineView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ public class LineView : Clutter.Actor {
private Mx.Button collapse_button = null;
private Clutter.Text text_container;

private struct LineSelection {
int start;
int end;
}

private LineSelection selection;

public bool is_prompt_line { get {return original_output_line.is_prompt_line;}}

public LineView(TerminalOutput.OutputLine output_line, LineContainer line_container) {
Expand Down Expand Up @@ -57,6 +64,8 @@ public class LineView : Clutter.Actor {

on_settings_changed(null);
Settings.get_default().changed.connect(on_settings_changed);

selection = LineSelection();
}

public void get_character_coordinates(int character_index, out int x, out int y) {
Expand All @@ -75,6 +84,44 @@ public class LineView : Clutter.Actor {
y = (int)(character_y + text_container.allocation.get_y());
}

public int get_coordinates_character(float x, float y) {
// TODO: coords_to_position seems to be buggy when working with non-latin characters
// return text_container.coords_to_position(x - text_container.get_x(), y - text_container.get_y());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on_text_container_motion_event should also make use of this utility method to avoid code duplication.

int byte_index;
int trailing;

float text_container_x;
float text_container_y;
text_container.get_transformed_position(out text_container_x, out text_container_y);

text_container.get_layout().xy_to_index(
(int)(x - text_container_x) * Pango.SCALE,
(int)(y - text_container_y) * Pango.SCALE,
out byte_index, out trailing);

return Utilities.byte_index_to_character_index(output_line.get_text(), byte_index) + 1;
}

public void set_selection(int start, int end, Selection.SelectionMode mode) {
selection.start = start;
selection.end = end;

if (mode == Selection.SelectionMode.WORD &&
(selection.start != 0 || selection.end != 0)) {
string text = output_line.get_text();

while (selection.start > 0 &&
!" \t\n\r-:\'\"".contains(text.substring(selection.start-1, 1))) {
selection.start--;
}
while (selection.end < text.char_count() &&
selection.end > 0 &&
!" \t\n\r-:\'\"".contains(text.substring(selection.end, 1))) {
selection.end++;
}
}
}

private bool on_text_container_motion_event(Clutter.MotionEvent event) {
// Apparently, motion event coordinates are relative to the stage
// (the Clutter documentation does not specify this)
Expand Down Expand Up @@ -167,6 +214,35 @@ public class LineView : Clutter.Actor {
text_container.set_markup(get_markup(output_line));
}

public string get_selected_text() {
int element_offset = 0;
int len = 0;
int offset = 0;
string text = "";
foreach (var text_element in output_line) {
// TODO: make this block of code less ugly
len = offset = 0;
if ((selection.end >= element_offset || selection.end == -1)&&
selection.start < element_offset + text_element.text.char_count()) {
offset = int.max(selection.start - element_offset, 0);
if (selection.end == -1 ||
selection.end > element_offset + text_element.text.char_count()) {
len = text_element.text.char_count() - offset;
} else
len = selection.end - offset - element_offset;
}

var offset_index = text_element.text.index_of_nth_char(offset);
var len_index = text_element.text.index_of_nth_char(offset + len);

text += text_element.text.substring(offset_index, len_index - offset_index);

element_offset += text_element.text.char_count();
}

return text;
}

private void update_collapse_button() {
collapse_button.style = Settings.get_default().theme.style;

Expand All @@ -179,20 +255,60 @@ public class LineView : Clutter.Actor {
private string get_markup(TerminalOutput.OutputLine output_line) {
var markup_builder = new StringBuilder();

int element_offset = 0;
int len = 0;
int offset = 0;

foreach (var text_element in output_line) {
// TODO: make this block of code less ugly
len = offset = 0;
if ((selection.end >= element_offset || selection.end == -1)&&
selection.start < element_offset + text_element.text.char_count()) {
offset = int.max(selection.start - element_offset, 0);
if (selection.end == -1 ||
selection.end > element_offset + text_element.text.char_count()) {
len = text_element.text.char_count() - offset;
} else {
len = selection.end - offset - element_offset;
}
}

var offset_index = text_element.text.index_of_nth_char(offset);
var len_index = text_element.text.index_of_nth_char(offset + len);

var text_attributes = text_element.attributes.get_text_attributes(
Settings.get_default().color_scheme, Settings.get_default().dark);
var markup_attributes = text_attributes.get_markup_attributes(
Settings.get_default().color_scheme, Settings.get_default().dark);

var pre_selection_text = Markup.escape_text(text_element.text.substring(0, offset_index));
var selection_text = Markup.escape_text(text_element.text.substring(offset_index, len_index - offset_index));
var post_selection_text = Markup.escape_text(text_element.text.substring(len_index));

// TODO: make selection stylable
if (markup_attributes.length > 0) {
markup_builder.append(
"<span" + markup_attributes + ">" +
Markup.escape_text(text_element.text) +
"</span>");
pre_selection_text +
"</span>" +
"<span background='#ffffff' foreground='#000000'>" +
selection_text +
"</span>" +
"<span" + markup_attributes + ">" +
post_selection_text +
"</span>"
);
} else {
markup_builder.append(Markup.escape_text(text_element.text));
markup_builder.append(
pre_selection_text +
"<span background='#ffffff' foreground='#000000'>" +
selection_text +
"</span>" +
post_selection_text
);

}
element_offset += text_element.text.char_count();
}

return markup_builder.str;
Expand Down
100 changes: 100 additions & 0 deletions src/Selection.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright © 2013–2014 Philipp Emanuel Weidmann <pew@worldwidemann.com>
*
* Nemo vir est qui mundum non reddat meliorem.
*
*
* This file is part of Final Term.
*
* Final Term is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Final Term is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Final Term. If not, see <http://www.gnu.org/licenses/>.
*/

public class Selection {
private TerminalOutput.CursorPosition start;
private TerminalOutput.CursorPosition finish;

public enum SelectionMode {
NORMAL,
WORD,
LINE,
COLUMN // Does not work
}

public SelectionMode mode {get; set;}

public Selection(TerminalOutput.CursorPosition position, SelectionMode mode) {
start = position;
this.mode = mode;
if(this.mode == SelectionMode.LINE) {
start.column = 0;
finish = start;
finish.column = 1;
}
}

public void update(TerminalOutput.CursorPosition position) {
finish = position;
}

public void get_line_range(int line, out int from, out int to) {
TerminalOutput.CursorPosition beginning = TerminalOutput.CursorPosition();
TerminalOutput.CursorPosition end = TerminalOutput.CursorPosition();

get_range(out beginning, out end);

from = to = 0;

if (mode == SelectionMode.COLUMN) {
if (line >= beginning.line && line <= end.line) {
from = int.min(beginning.column, end.column);
to = int.max(beginning.column, end.column);
}
} else if (mode == SelectionMode.WORD) {
if (line == beginning.line) {
from = beginning.column;
}
if (line >= beginning.line && line < end.line) {
to = -1;
} else if (line == end.line) {
to = end.column;
}
} else if (mode == SelectionMode.LINE) {
if (line >= beginning.line && line <= end.line) {
from = 0;
to = -1;
}
} else {
if (line == beginning.line) {
from = beginning.column;
}
if (line >= beginning.line && line < end.line) {
to = -1;
} else if (line == end.line) {
to = end.column;
}
}
}

// end position can be before or after start position
// this function returns them in correct order
public void get_range(out TerminalOutput.CursorPosition beginning, out TerminalOutput.CursorPosition end) {
if (start.compare(finish) > 0) {
beginning = finish;
end = start;
} else {
beginning = start;
end = finish;
}
}
}< 45C0 /span>
Loading
0