TL; DRMecz pozycja kursora na podciągu po tekście zastąpić
Mam funkcję zamiany tekstu, położenie strun i kursora (numer) i muszę dostać skorygowaną pozycję (numer) do nowego łańcucha, który jest stworzony z funkcji wymienić jeśli długość jeżeli zmiana strun:
input and cursor position: foo ba|r text
replacement: foo -> baz_text, bar -> quux_text
result: baz_text qu|ux_text text
input and cursor position: foo bar| text
replacement: foo -> baz_text, bar -> quux_text
result: baz_text quux_text| text
input and cursor position: foo bar| text
replacement: foo -> f, bar -> b
result: f b| text
input and cursor position: foo b|ar text
replacement: foo -> f, bar -> b
result: f b| text
problemem jest to, że można używać podciąg na oryginalnym tekście, lecz następnie zastąpienie nie będzie pasował całe słowo, więc muszą być wykonane dla całego tekstu, ale potem podłańcuch nie będzie pasował do zamiennika.
Nie mam też nic przeciwko rozwiązaniu, w którym kursor znajduje się zawsze na końcu słowa, gdy oryginalny kursor znajduje się w środku zastąpionego słowa.
i teraz moja realizacja, w jQuery Terminal Mam tablicę funkcji formatujących w:
$.terminal.defaults.formatters
przyjmują ciąg i powinien on powrócić nowy ciąg działać dobrze z wyjątkiem tym przypadku:
kiedy Mam formatter, który zmienia długość, jeśli przerwie linię poleceń, na przykład ten formatator:
$.terminal.defaults.formatters.push(function(string) {
return string.replace(/:smile:/g, 'a')
.replace(/(foo|bar|baz)/g, 'text_$1');
});
wtedy pozycja kursora była błędna, gdy polecenie li ne otrzymasz nowy ciąg.
ja staram się to naprawić, ale to nie działa zgodnie z oczekiwaniami, wewnętrzna terminalu wyglądać tak,
przy zmianie position
mam skrzynie kolejna zmienna formatted_position
to użycie w wierszu poleceń wyświetl kursor. aby ta wartość używam to:
formatted_position = position;
var string = formatting(command);
var len = $.terminal.length(string);
var command_len = $.terminal.length(command);
if (len !== command_len) {
var orig_sub = $.terminal.substring(command, 0, position);
var orig_len = $.terminal.length(orig_sub);
var formatted = formatting(orig_sub);
var formatted_len = $.terminal.length(formatted);
if (orig_len > formatted_len) {
// if formatting make substring - (text before cursor)
// shorter then subtract the difference
formatted_position -= orig_len - formatted_len;
} else if (orig_len < formatted_len) {
// if the formatted string is longer add difference
formatted_position += formatted_len - orig_len;
}
}
if (formatted_position > len) {
formatted_position = len;
} else if (formatted_position < 0) {
formatted_position = 0;
}
$ i $ .terminal.length .terminal.substring są pomocnicze funkcje, które są świadome formatowania zacisk (tekst, który wygląda tak [[b;#fff;]hello]
), jeśli będziesz pisać rozwiązanie można użyć normalny tekst i użycie metod łańcuchowych.
problemem jest to, że kiedy przesunąć kursor w środku wyrazu, który zmienił
to niby pracy, gdy tekst jest dłuższy, ale na krótszy ciąg skoku kursora w prawo, gdy tekst jest w środek słowa, które zostało zastąpione.
ja staram się to naprawić, jak również przy użyciu tego kodu:
function find_diff(callback) {
var start = position === 0 ? 0 : position - 1;
for (var i = start; i < command_len; ++i) {
var substr = $.terminal.substring(command, 0, i);
var next_substr = $.terminal.substring(command, 0, i + 1);
var formatted = formatting(next_substr);
var substr_len = $.terminal.length(substr);
var formatted_len = $.terminal.length(formatted);
var diff = Math.abs(substr_len - formatted_len);
if (diff > 1) {
return diff;
}
}
return 0;
}
...
} else if (len < command_len) {
formatted_position -= find_diff();
} else if (len > command_len) {
formatted_position += find_diff();
}
ale myślę uczynić go jeszcze gorzej ponieważ posiadał znaleźć diff, gdy kursor znajduje się przed lub w środku zastąpiła słowem i powinno Znajdź różnicę tylko wtedy, gdy kursor znajduje się w środku zastąpionego słowa.
można zobaczyć wynik z moich prób w tym codepen https://codepen.io/jcubic/pen/qPVMPg?editors=0110 (które pozwalają wpisać emoji i foo bar baz zastępowane przez text_$1
)
UPDATE:
mam zrobić to rodzaj pracować z tym kodem:
// ---------------------------------------------------------------------
// :: functions used to calculate position of cursor when formatting
// :: change length of output text like with emoji demo
// ---------------------------------------------------------------------
function split(formatted, normal) {
function longer(str) {
return found && length(str) > length(found) || !found;
}
var formatted_len = $.terminal.length(formatted);
var normal_len = $.terminal.length(normal);
var found;
for (var i = normal_len; i > 1; i--) {
var test_normal = $.terminal.substring(normal, 0, i);
var formatted_normal = formatting(test_normal);
for (var j = formatted_len; j > 1; j--) {
var test_formatted = $.terminal.substring(formatted, 0, j);
if (test_formatted === formatted_normal &&
longer(test_normal)) {
found = test_normal;
}
}
}
return found || '';
}
// ---------------------------------------------------------------------
// :: return index after next word that got replaced by formatting
// :: and change length of text
// ---------------------------------------------------------------------
function index_after_formatting(position) {
var start = position === 0 ? 0 : position - 1;
var command_len = $.terminal.length(command);
for (var i = start; i < command_len; ++i) {
var substr = $.terminal.substring(command, 0, i);
var next_substr = $.terminal.substring(command, 0, i + 1);
var formatted_substr = formatting(substr);
var formatted_next = formatting(next_substr);
var substr_len = length(formatted_substr);
var next_len = length(formatted_next);
var test_diff = Math.abs(next_len - substr_len);
if (test_diff > 1) {
return i;
}
}
}
// ---------------------------------------------------------------------
// :: main function that return corrected cursor position on display
// :: if cursor is in the middle of the word that is shorter the before
// :: applying formatting then the corrected position is after the word
// :: so it stay in place when you move real cursor in the middle
// :: of the word
// ---------------------------------------------------------------------
function get_formatted_position(position) {
var formatted_position = position;
var string = formatting(command);
var len = $.terminal.length(string);
var command_len = $.terminal.length(command);
if (len !== command_len) {
var orig_sub = $.terminal.substring(command, 0, position);
var orig_len = $.terminal.length(orig_sub);
var sub = formatting(orig_sub);
var sub_len = $.terminal.length(sub);
var diff = Math.abs(orig_len - sub_len);
if (false && orig_len > sub_len) {
formatted_position -= diff;
} else if (false && orig_len < sub_len) {
formatted_position += diff;
} else {
var index = index_after_formatting(position);
var to_end = $.terminal.substring(command, 0, index + 1);
//formatted_position -= length(to_end) - orig_len;
formatted_position -= orig_len - sub_len;
if (orig_sub && orig_sub !== to_end) {
var formatted_to_end = formatting(to_end);
var common = split(formatted_to_end, orig_sub);
var re = new RegExp('^' + $.terminal.escape_regex(common));
var to_end_rest = to_end.replace(re, '');
var to_end_rest_len = length(formatting(to_end_rest));
if (common orig_sub !== common) {
var commnon_len = length(formatting(common));
formatted_position = commnon_len + to_end_rest_len;
}
}
}
if (formatted_position > len) {
formatted_position = len;
} else if (formatted_position < 0) {
formatted_position = 0;
}
}
return formatted_position;
}
to nie działa na jednym przypadku po wpisaniu emotikonów jako pierwszego znaku, a kursor znajduje się w środku: smile: słowo. Jak naprawić funkcję get_formatted_position, aby mieć poprawną, stałą pozycję po zamianie?
UPDATE: mam poprosić innego i proste pytanie i mam rozwiązanie przy użyciu funkcji trackingReplace że akceptują regex i ciąg, więc mam zmienić API dla formatek zaakceptować tablicę z regex i ciąg wzdłuż funkcji Correct substring position after replacement
Czy jesteś pewien, że przesunięcie kursora na zastąpione słowo jest prawidłowe? Dla mnie wydaje się to dość mylące. Zajrzałbym do Worda lub do google docs, jeśli nie poruszą go na początku ani na końcu. – Akxe
@Akxe to zupełnie inny przypadek niż słowo lub google docs, ponieważ tekst jest zastępowany podczas wpisywania nie, gdy zastępujesz tekst, jak w funkcji wyszukiwania/zamiany. I wygląda to bardzo dziwnie, gdy nie zmieniasz pozycji, ponieważ możesz być końcem końca tekstu, który ma długość 10, a zastąpiony tekst jest równy 3, a otrzymasz pozycję 10, która powinna wynosić 3. – jcubic
Miałem na myśli, jeśli zamień słowo, w którym znajduje się twój kursor, wtedy lepiej jest umieścić kursor z przodu lub po nowym zastąpionym słowie. A Word na pewno ma opcję do zastąpienia. – Akxe