Re[22]: Rsdn.Editor
От: Воронков Василий Россия  
Дата: 24.01.06 23:46
Оценка:
Здравствуйте, VladD2, Вы писали:

ВВ>>Какое-то описание есть здесь. Причем это не самый эффективный алгоритм.

VD>Сдается мне, что это в данном случае не причем.

Честно, не хочется тут особо спорить. Помнится, есть более подробное описание этого в Inside SharpDevelop. Была еще и интересная книжка про написание текстовых редакторов, но ссылки не приведу, так как ее надо искать, а интернет мне на работе урезали за то, что порнуху качал.

ВВ>> Скорость по большому счету упирается в отрисовку.

VD>Редактирования? Да.

Кстати, а почему для рисования TextRenderer не используется? Или он совсем недавно появился.

ВВ>>Не, ну я же не против абстракций. Собственно, я вообще не пытаюсь критиковать реализацию.

VD>Кстати, я не против критики. Я очень за критику. Я только хочу, чтобы она была продуманной. А то у меня со временем ужасные проблемы и не хочется убивать его на борьбу с догмами. (не обижайся) По этому если ты показывашь пальцем и говоришь, "вот это мне кажется странным (глупым, непродуманным...)", я постораюсь разобраться и подумать не ошибся ли я. Возможно даже переосмыслить свою позицию. Но когда все сводится к "ой, а не много ли тут памяти расходуется", то разговаривать то в общем-то не очем. Ведь предмет разговора не определен.

ОК, я понял. "Мне кажется странным, что работа со строками ведется в лоб, а не используется какой-либо из алгоритмов, позволяющих эффективно модифицировать строки". Так лучше?

ВВ>>На самом деле я пытался въехать во что упирается работа с текстами только по-строчно. Ведь все-таки string[] — это скорее _представление_ данных, чем сам данные.

VD>Во что упирается? Одна строка занимается, другая освобождается. В итоге мы имеем новую строку у которой длинна больше или меньше. ЖЦ при одной из сборок мусора сожмет кучу и мы заплатим только за разницу. Ну, еще мы заплатим временем затрачиваемым ЖЦ на работу. Но ведь мы уже оговорились, что со скорость воде как проблем нет? Далее какое-то место уйдет на хранение команы. Но это плата за возможность сделать анду и реду. Все промежуточные команды опять же подберет ЖЦ. Если вдруг когда-то хранение команд покажется черезчур накладным, то можно сбросить их на диск. Но вот пока что мне не кажется это нужным (хотя думл я об этом еще когда проектирваол редактирование).

Я немножко не об этом. Бог с ней, с памятью. Непонятно почему данные хранятся как, фактически, массив строк. Это было наиболее удобным/эффективным решением? Потому что на настоящий момент по крайней мере одна проблема имеет место быть — то вся работа со стилями как бы "привинчена" к конкретной строке, что несколько неудобно.

ВВ>>Да, согласен. Но чем gap buffer этому мешает?

VD>А что он мне даст? Читаем из твой ссылки:
VD>

A gap buffer is a structure that models a string but allows relatively
VD>efficient insertion of text somewhere in the middle.

VD>У меня есть проблемы с производительностью? А вот на это efficient прийдется потратить память чтобы организовать дыры.

Ну ты же не жалуешься на то, что List<String> жрет слишком много памяти по сравнению со string[]. А здесь аналогия примерно такая же — да, мы оставляем дыры, тратим лишние байты, но благодаря этому можем делать in-place модицирование строки. Впрочем, достаточно об этом.
Кстати, неплохой идеей было бы как-то выделить низкоуровевый код отвечающий за работу с текстом — как это сделано в шарп-девелопе например. Чтобы при желании, если например потребуется сделать на основе Rsdn.Editor редактор для сверх-больших файлов можно было бы легко и просто это участок поменять.

VD>Ты забавно мыслиь. Ты пыташся сравнить работу редактора с (внимание!) интерфейсом Сцинтилы. Если сравнить интерфейсы (а у Сцинтилы он весь из сообщений в стиле Виндовс стостит), то уверяю тебя интерфейс Rsdn.Editor куда проще. От част просто потому, что в нем не реализованы некторые вещи , а от части потому, что нет необходимости возиться с низкоуровневыми абстракциями вроде char* и т.п.


А чем отличается "низкоуровневая абстракция" char* от System.String? Наличием звездочки?

VD>Например, я сразу ввел понятие координат и пересчеты между координатами представления и документа. В синтиле этого нет. Казалось бы проще... Но на самом деле разбираясь все время надо понимать, что вот этот int — это номер строки в документе, а вот этот — это в колонка в представлении. В итоге сам черт ноку сломит. То же самео с командами. Команда Сцинтилы — это один класс с кучей полей которые используются в разных случаях. У меня это набор классов которые используются только там где это возможно и нужно. Причем для большинства классов у меня есть визуализация в отладчике. В то же время в сцинтиле одно преобразование из/в utf-8 и хнанение байтов стилей вперемешку с байтами текста так шифрует суть происходящего, что даже строку то увидеть не возможно. Я же четко отделил стили от текста и храню его в виде простой строки.


Дык или я чего-то не понял или текст у тебя все-таки хранится не в виде простой строки, а виде _массива_ строк.

VD>>>Теперь о реализации. В Сцинтиле, точно так же как и в Rsdn.Editor применяются команды редактирования. Разница только в том, что у меня разные типы команд описываются разными классами и составляют иерархию:

VD>>>
VD>>>Command - абстрактный
VD>>>    MultiCommand
VD>>>    ModifyTextCommand - абстрактный
VD>>>        InsertCommand 
VD>>>        DeleteCommand
VD>>>        UpdateCommand
VD>>>

VD>>>в которой все конкретные (не абстрактные) классы реализуют ICommand.

ВВ>>А зачем?


VD>Затем, чтобы видеть что рельно происходит. Чтобы отделять действия по вставке от действий по редактированию. Прицип действия моей команды очень прост. У любой команды можно вызвать ICommand.Execut() и ты получишь а) действия связанные с командой, б) команду обратную этой (то есть если выполнить полученную команду, то действия предыдущей будут откачены). А почему иерархия классов, а не "все в одном"? Дык между прочим InsertCommand должна хранить текст, DeleteCommand только координаты удаляемого текста, а UpdateCommand и то и другое. Ну, а MultiCommand вообще должны хранить список команд которые нужно выполнить как единую транзацию. Так что это Сцинтила расходует память по напрасну, так как ее команда всегда хранит "все что нужно".


VD>Но делал иерархию я не для этого. Иерархия позволяет хорошо отделить логику. В купе с наследованием реализации, которое позволяет выделить общую логику, это позволяет очень хоршо отделить разную логику друг от дурга и в то же время получить отличную абстаркцию.


А как будет в дальнейшем расширяться функциональность? Т.е. ты описал через эти интерфейсы примитивные операции, но помимо них будут и другие — да и собственно уже есть. Почему нет, например, SetStyleCommand?
Я не против идеи, идея интересная, но зачем 1) выставлять наружу детали реализации (всякие InsertCommand, DeleteCommand и пр.); это должны ИМХО быть частные реализации, иначе представь как загрузится АПИ если "дописать" сюда команд, 2) такой подход должен быть наверное общим, а не избирательным, а то придется смотреть что реализовано в качестве команды, а что в качестве DocumentRow.XXX.

VD>Возможно отчасти потому, что Сцинтиле много лет и всей все уже отработно, а у меня работа со стилями откровенно не доделана.


Вот, было подозрение И наверное лучше сначала доделать.

VD>При этом исчезает еще одна проблема. Ты не ограничен количеством битов отводимых на стиль. Размер массива может быть любым! А вот в Сцинтиле, если мне не изменяет память, количество стилей не дожно привышать 16.


Да ладно уж, там почти целый байт. Кстати int32 мне тоже кажется небольшим излишеством — хотелось бы например иметь возможность ассоциировать какую-нибудь custom-информацию со строкой (например, для browser-like навигации по тексту), не отводить же для этого очередной Int?

VD>Понятно, что для одного-двух язяков не трудно написать стайлер вручную. В Сцинтиле все стайлеры написаны вручную (Уроды, блин! Правда есть редакторы на базе Сцинтилы которые имеют свои генераторы стайлеров.). Но мы не индусы . Так что нужно сделать генератор лексеров. Самый простой и продуктивный путь — это выдрать генератор детерминированного конечного автомата (ДКА) из CocoR и изменив в нем кодогенерацию порождать эффективные стайлеры вместо CocoR-ного Scanner-а.


А как ты себе представляешь генератор лексеров? Т.е. чего он будет генерировать и на основе чего? У меня кстати была в свое время сделать что-то типа враппера над кокой — т.е. на основе простой описанной в ХМЛ грамматике генерится EBNF-грамматика для коки, на основе которой уже динамически собирается парсер. Однако особых бенефитов такой способ не даст, а гемора будет не много.
Мне казалось, что не так сложно написать ручками лексер который подойдет для большинства грамматик, а если уж будет что-то слишком навороченное, то можно и свой написать, так как всевозможные случаи все равно не предусмотришь.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.