Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 07:52
Оценка:
Обнаружил, что компилятор некорректно обрабатывает директиву line. Сразу небольшой пример:

class Class
{
  Foo() : void
  {
    def a = 1;
    
#line 100 "C:\\Temp\\foo.txt"
    def b = 1;
#line default
  }
}


внутри блока line не работают хинты и автокомплит.

Компилятор присваивает всем элементам внутри директивы line значение location, указывающее на внешний файл. Интеграция использует локальные координаты каретки (line/column) для поиска выражения для автокомплита. Для этого интеграция перебирает выражения внутри метода, сопоставляя кординаты каретки и координаты из location выражений. Поскольку выражения внутри блока line имеют позиции, указывающие на внешний файл, поиск выражений внутри блока закачивается неудачей.

Из за некорректной обработки директивы также не работает автодополнение и хинты для серверных блоков внутри aspx страниц <% %>. ASP.NET парсит aspx страницу, выделяя серверные блоки, формирует из них виртуальный исходник и скармливает компилятору уже его, а не сырой aspx файл. Фактически компилятор и интеграция работают с виртуальным исходником, а студия на лету маппирует координаты между ним и aspx файлом. Для маппинга координат используются директивы line.

Поэтому некорректная обработка директив line не дает реализовать автокомплит и хинты для выражений, содержащихся <% %> блоков aspx файлов. Черт с ними с хинтами, но автокомплит думаю очень нужен, особено при использовании статически типизованных mvc представлений .

Для исправления нужно хранить позицию, задаваемую директивой line в отдельном свойстве класса Located. Это свойство (ExternalLocation) следует использовать только при генерации меток для pdb файла и при формировании текста сообщений об ошибках. Во всех остальных случаях следует использовать Location, указывающий на позиции в исходном файле. Кстати, метки для pdb файла формировались некорректно, из за этого не работали брекпоинты внутри блоков <% %> — это я уже исправил.

И самый главный вопрос — как думаете, стоит этим сейчас заняться, или фича никому не интересна?

p.s. Нужно еще продумать, что делать со свойством ExternalLocation при модификации кода макросами. Сейчас макросы могут подкручивать локации выражений, нужно ли это делать и для ExternalLocation? — пока я думаю, что этого делать не нужно.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re: Некорректная обработка директивы #line
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.04.10 11:28
Оценка:
Здравствуйте, seregaa, Вы писали:

S>Для исправления нужно хранить позицию, задаваемую директивой line в отдельном свойстве класса Located.


Может быть поступить проще?... Просто игнорировать директиву line при работе в режиме интеграции?

S>Это свойство (ExternalLocation) следует использовать только при генерации меток для pdb файла и при формировании текста сообщений об ошибках.


Нда, вот для сообщений действительно нужно использовать данные line.

Боюсь — это слишком большие изменения.

S>И самый главный вопрос — как думаете, стоит этим сейчас заняться, или фича никому не интересна?


На счет "интересна" ответить не могу. Конечно было бы не плохо получить интеллисенс во внешних дслях.

Думаю тут все зависит от того насколько это можно сделать малой кровью.

Ты разобрался как организована поддержка интеллисенса в aspx-файлах?
Возможно проще было бы вмешаться в этот процесс и реализовать все по-своему.

S>p.s. Нужно еще продумать, что делать со свойством ExternalLocation при модификации кода макросами. Сейчас макросы могут подкручивать локации выражений, нужно ли это делать и для ExternalLocation? — пока я думаю, что этого делать не нужно.


Еще более сложный вопрос, "что делать при изменении кода aspx-файла?". Ведь любое его изменение может привести к несоответствию локешонов в сгенерированном n-фафеле.

Отличным решением было бы самостоятельно обрабатывать интеллисенс для aspx-файлов. Тогда можно было бы просто извлегать строки с кодом и типизировать их динамически. Они, в большинстве случаев, будут очень мелкими, что не займет много времени. При этом мы будет иметь все данные о реальных локешонах.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Некорректная обработка директивы #line
От: hardcase Пират http://nemerle.org
Дата: 27.04.10 13:27
Оценка:
Здравствуйте, seregaa, Вы писали:


S>Обнаружил, что компилятор некорректно обрабатывает директиву line. Сразу небольшой пример:


S>
S>class Class
S>{
S>  Foo() : void
S>  {
S>    def a = 1;
    
S>#line 100 "C:\\Temp\\foo.txt"
S>    def b = 1;
S>#line default
S>  }
S>}
S>


А для чего это вообще может пригодиться?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 14:24
Оценка: 11 (2)
Здравствуйте, hardcase, Вы писали:

H>А для чего это вообще может пригодиться?


Этот механизи используется студией для поддерджки автодополнения и хинтов в блоках <%%> aspx файлов.

Вот вкратце как работает автодополнение для обычных файлов (мое сегодняшнее понимание процесса):

Как только *.n файл открывается в редакторе, для него создается объект NemerleSource, обеспечивающий поддержку интеллисенса. Этот объект обрабатывает запросы на автодополнение, отображение хинтов, а также события редактирования файла. Для доступа к содержимому файла используется буфер, передаваемый в конструктор NemerleSource. Это позволяет всегда иметь дело с самым свежим содержимым файла, даже еще не сохраненным на диск. При каждом редактировании файла запускается процесс обновления объектной модели кода CompileUnit. Эта модель используется методами поддержки интеллисенса.

А вот как это работает для aspx файлов:

Как только aspx файл открывается в редакторе, для него тоже создается NemerleSource, хотя aspx файл по сути не является корректным исходником на Немерле. Для такого файла создается два буфера — primary и secondary. Первый связан с непосредственным содержимым aspx файла, а второй — со сгенерированным по aspx виртуальным исходником на Немерле. Виртуальный исходник генерится так: инфраструктура asp.net парсит aspx файл и создает независимую от языка объектную модель кода страницы, которая затем переводится в код с помощью конкретного генератора, в нашем случае это NemerleCodeGenerator. Объектная модель содержит ссылки на aspx файл в виде элементов CodeLinePragma, который генератор Немерле генерирует как директивы #line.

Затем содержимое вторичного буфера парсится с помощью простейшего парсера и обнаруженные блоки #line сопоставляются с <%%> блоками. Эта информация в дальнейшем используется для трансляции локаций первичного буфера в локации вторичного и наоборот.

Вторичный (сгенерированный) буфер и передается в конструктор NemerleSource. При этом запросы от редактора, открытого для первичного буфера (aspx), поступают в NemerleSource, созданный по вторичному буферу, транслируясь по пути из одной системы кординат в другую. Т.е. если нажать в aspx редакторе в строке 10 позиции 5 клавишу ".", то NemerleSource получит сигнал OnCommand с пересчитаными координатами, например 78 и 8.

Для того, чтобы вся эта махина заработала, нужно уметь сопоставлять блоки в сгенерироанном коде и исходные <%%> блоки aspx файла. Поэтому отказаться от директивы #line не получится. А с директивами line не работает поиск выражений по координатам, поскольку локации выражений внутри блоков line имеют некорректные значения.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[3]: Некорректная обработка директивы #line
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.04.10 14:34
Оценка:
Здравствуйте, seregaa, Вы писали:

S>Этот механизи используется студией для поддерджки автодополнения и хинтов в блоках <%%> aspx файлов.


Боюсь, что там все сложнее. Для выдачи сообщений об ошибках это использовать можно. А вот для комплита — вряд ли. Как минимум в line не задается отступ (char). А без него нельзя точно понять о каком фрагменте идет речь. Потом комплит происходит именно в aspx-файле, так что обрабатываться он должен именно там. Я не знаю как вмешаться в этот процесс.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 14:35
Оценка:
Здравствуйте, VladD2, Вы писали:

S>>Для исправления нужно хранить позицию, задаваемую директивой line в отдельном свойстве класса Located.

VD>Может быть поступить проще?... Просто игнорировать директиву line при работе в режиме интеграции?

хм, интересная идея.

S>>Это свойство (ExternalLocation) следует использовать только при генерации меток для pdb файла и при формировании текста сообщений об ошибках.

VD>Нда, вот для сообщений действительно нужно использовать данные line.
VD>Боюсь — это слишком большие изменения.

Можно попробовать модифицировать сообщения компилятора, заменяя на лету имя файла и номера строк. Это решение будет действительно "малой кровью". Я временно попробовал отключить обработку директивы line и интеллисенс благополучно заработал.

VD>Ты разобрался как организована поддержка интеллисенса в aspx-файлах?

VD>Возможно проще было бы вмешаться в этот процесс и реализовать все по-своему.

Немного поразбирался, и похоже что сделать это непросто, см ниже.

S>>p.s. Нужно еще продумать, что делать со свойством ExternalLocation при модификации кода макросами. Сейчас макросы могут подкручивать локации выражений, нужно ли это делать и для ExternalLocation? — пока я думаю, что этого делать не нужно.


VD>Еще более сложный вопрос, "что делать при изменении кода aspx-файла?". Ведь любое его изменение может привести к несоответствию локешонов в сгенерированном n-файле.


Здесь все работает так же, как и для обычных файлов *.n — все действия с aspx передаются в NemerleSource, связанный с кодом, сгенерированный по aspx странице (см мой ответ hardcase). А NemerleSource вызывает на каждый чих BeginUpdateCompileUnit.

VD>Отличным решением было бы самостоятельно обрабатывать интеллисенс для aspx-файлов. Тогда можно было бы просто извлегать строки с кодом и типизировать их динамически. Они, в большинстве случаев, будут очень мелкими, что не займет много времени. При этом мы будет иметь все данные о реальных локешонах.


Можно, но тогда придется самому парсить aspx и строить класс по блокам <%%>. Блоки внедренного кода компилируются ведь не сами по себе, а как часть методов класса aspx страницы. Для того, чтобы правильно построить этот класс нужно распарсить все заголовки (директивы) aspx файла, и блоки <%%>, <script runat=server>. Более того, разметка <%%> может встречаться внутри серверных контролов, в этом случае построение модели страницы становится еще более нетривиальным. Только после этого можно будет корректно типизировать сгенерированный метод.

Встроенный парсер помечен как internal, поэтому переиспользовать его не получится (((
Мне все больше и больше нравится идея с игнорирование line при компиляции в режиме интеграции и правкой на лету сообщений об ошибках.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[4]: Некорректная обработка директивы #line
От: Аноним  
Дата: 27.04.10 14:36
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, seregaa, Вы писали:


S>>Этот механизи используется студией для поддерджки автодополнения и хинтов в блоках <%%> aspx файлов.


VD>Боюсь, что там все сложнее. Для выдачи сообщений об ошибках это использовать можно. А вот для комплита — вряд ли. Как минимум в line не задается отступ (char).


А разве отступ делается не таким как в ASPX файле?
Re[5]: Некорректная обработка директивы #line
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.04.10 14:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А разве отступ делается не таким как в ASPX файле?


Думаю — нет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 14:41
Оценка:
Здравствуйте, Аноним, Вы писали:

VD>>Боюсь, что там все сложнее. Для выдачи сообщений об ошибках это использовать можно. А вот для комплита — вряд ли. Как минимум в line не задается отступ (char).

А>А разве отступ делается не таким как в ASPX файле?

Да, отступ сохраняется такой же, как и в aspx файле. Это и позволяет точно установить исходный фрагмент.

Для сохранения отступов и прочих особенностей форматирования, код блока внедряется в объктную модель страницы как CodeSnippetStatement, т.е. как текст, без предварительного разбора.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[6]: Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 14:51
Оценка:
Здравствуйте, VladD2, Вы писали:

А>>А разве отступ делается не таким как в ASPX файле?

VD>Думаю — нет.

делается )

вот исходный фрагмент:
<% // comment
   def i=0;
       i++;             i--;
i+=10;
%>


а вот кусок сгенерировнного файла:
private __Render__control1 (__w : System.Web.UI.HtmlTextWriter,  parameterContainer : System.Web.UI.Control) : void
{

#line 1 "C:\Users\Sergey\Documents\Visual Studio 2008\Projects\WebApplication19\WebApplication19\Default.aspx"
   // comment
   def i=0;
       i++;             i--;
i+=10;

#line default
}
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[7]: Некорректная обработка директивы #line
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.04.10 15:10
Оценка:
Здравствуйте, seregaa, Вы писали:


S>делается


ОК. Но все равно без перехвата действий в aspx-файлах получить качественный интелисенс будте невозможно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Некорректная обработка директивы #line
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.04.10 15:11
Оценка:
Здравствуйте, seregaa, Вы писали:

S>Для сохранения отступов и прочих особенностей форматирования, код блока внедряется в объктную модель страницы как CodeSnippetStatement, т.е. как текст, без предварительного разбора.


А если его нужно обернуть в другой кусок код (ну, скажем для вывода в поток), то код не может поехать?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 15:18
Оценка:
Здравствуйте, VladD2, Вы писали:

S>>делается

VD>ОК. Но все равно без перехвата действий в aspx-файлах получить качественный интелисенс будте невозможно.

Не совсем понял, о перехвате каких действий идет речь. Сейчас NemerleSource, связанный со сгенерированным кодом, получает все события от редактора aspx файла. Включая нажатия клавиш, перемещение каретки, запросы хинтов и т.д. Единственное — все координаты попадают в NemerleSource оттранслированные в систему координат виртуального файла. Но их всегда можно сконвертировать обратно, апи для этого есть.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[7]: Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 15:19
Оценка:
Здравствуйте, VladD2, Вы писали:

S>>Для сохранения отступов и прочих особенностей форматирования, код блока внедряется в объктную модель страницы как CodeSnippetStatement, т.е. как текст, без предварительного разбора.


VD>А если его нужно обернуть в другой кусок код (ну, скажем для вывода в поток), то код не может поехать?


Чет не могу предсавить примера. Но раз уж студия использует такой подход, думаю она знает что делает )
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[3]: Некорректная обработка директивы #line
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.04.10 15:46
Оценка:
Здравствуйте, seregaa, Вы писали:

S>Вот вкратце как работает автодополнение для обычных файлов (мое сегодняшнее понимание процесса):


А это понимание основано на чем? Предположения? Или это изучение вопроса под отладчиком и Рефлектором?

S>Как только *.n файл открывается в редакторе, для него создается объект NemerleSource, обеспечивающий поддержку интеллисенса.


Начнем с того, что этот файл, скорее всего не подключен ни к какому проекту. Стало быть получить по нему интелисенс для немерла будет наивозможно.

S>Этот объект обрабатывает запросы на автодополнение, отображение хинтов, а также события редактирования файла.


А при редактировании все содержимое изменяется, или только участок файла соответствующий?

S>Для доступа к содержимому файла используется буфер, передаваемый в конструктор NemerleSource. Это позволяет всегда иметь дело с самым свежим содержимым файла, даже еще не сохраненным на диск.


В принципе грамотно. Если они сделали пренаправление качественно, то можно попробовать это дело поддерживать.

S>При каждом редактировании файла запускается процесс обновления объектной модели кода CompileUnit. Эта модель используется методами поддержки интеллисенса.


Вот этого я не понял. Что и кем запускается? Это уже должна делать наша интеграция (наш код)... как реакция на изменение исходника (на событие изменения).

S>А вот как это работает для aspx файлов:


S>Как только aspx файл открывается в редакторе, для него тоже создается NemerleSource, хотя aspx файл по сути не является корректным исходником на Немерле.


А если aspx закрыт, исходника нет?

S>Виртуальный исходник генерится так: инфраструктура asp.net парсит aspx файл и создает независимую от языка объектную модель кода страницы, которая затем переводится в код с помощью конкретного генератора, в нашем случае это NemerleCodeGenerator. Объектная модель содержит ссылки на aspx файл в виде элементов CodeLinePragma, который генератор Немерле генерирует как директивы #line.


Это все ясно и не так интересно. Больше интересен сам процесс создания этого исходника.
Этот исходник нужно как-то отловить, понять что он относится к проекту и кодключить его к этому самому проекту. Ну, а если исходник закрывается, то его нужно отключить от проекта.

Если же этот исходник всегда присутствует на диске и подключен к проекту (а как без этого его скомпилировать иначе?), то вопрос решается сам собой.

S>Затем содержимое вторичного буфера парсится с помощью простейшего парсера и обнаруженные блоки #line сопоставляются с <%%> блоками. Эта информация в дальнейшем используется для трансляции локаций первичного буфера в локации вторичного и наоборот.


Этого не понял. Что за "обнаруженные блоки #line"? Зачем их обнаруживать? Они же просто в исходник помещаются (генерируемый).

S>Вторичный (сгенерированный) буфер и передается в конструктор NemerleSource. При этом запросы от редактора, открытого для первичного буфера (aspx), поступают в NemerleSource, созданный по вторичному буферу, транслируясь по пути из одной системы кординат в другую. Т.е. если нажать в aspx редакторе в строке 10 позиции 5 клавишу ".", то NemerleSource получит сигнал OnCommand с пересчитаными координатами, например 78 и 8.


Ну, тогда нужно просто попробовать отключить обработку #line в режиме интелисенса и посмотреть что из этого получится. Понятно, что сообщения об ошибках нучнут показывать на сгенерированный буфер, но это уже дело десятое. Главное, что будет ясно прав ты или нет. И рабочая ли получается схема.

S>Для того, чтобы вся эта махина заработала, нужно уметь сопоставлять блоки в сгенерироанном коде и исходные <%%> блоки aspx файла. Поэтому отказаться от директивы #line не получится. А с директивами line не работает поиск выражений по координатам, поскольку локации выражений внутри блоков line имеют некорректные значения.


Чтобы эта механика заработала нужно просто игнорировать эти #line. Возникнут проблемы с тем куда указывают сообщения об ошибках, но это уже отдельный разговор. К тому же работать и так будет можно. Ведь сообщения будут указывать в сгенерированный код (так что проблему понять будет можно). Плюс при компиляции сообщения будут указывать куда надо.

Так что просто залезь в Lexer.n. Находи там строку 1464. Там расположен код обработки этой директив:
      | "line" =>
        eat_spaces ();

        mutable c = peek_or_white ();

        def (new_line, new_file) =
          if (c == 'd')
          {
            if (read_word () == "default")
            {
              eat_spaces ();
              when (read_to_the_end_of_line () != "")
                throw LexerBase.Error ("extra tokens after directive");
              (-1, null)
            }
            else
              throw LexerBase.Error ("expecting line number or `default' indicator")
          }
          else
          {
            def num = StringBuilder ();
            def loop ()
            {
              when (char.IsDigit (c))
              {
                ignore (num.Append (read ()));
                c = peek_or_white ();
                loop ();
              }
            }

            loop ();
            
            if (num.Length > 0)
              (Int32.Parse (num.ToString ()), read_to_the_end_of_line ().Trim ().Trim ('\"'))
            else
            {
              Message.Error (this.Location, "expecting line number or `default' indicator");
              _ = read_to_the_end_of_line ();
              (-1, null)
            }
          };

        if (new_line == -1)
        {
          when (line_stack != -1)
            line = line - line_start + line_stack;
          file_idx = Location.GetFileIndex (file_real);
          line_stack = -1;
        }
        else
        {
          // if there is already something on stack, bring real line first
          when (line_stack != -1)
            line = line - line_start + line_stack;
          line_start = new_line;
          line_stack = line;
          line = new_line;
          when (new_file != "") 
            file_idx = Location.GetFileIndex (new_file);
        }


В него надо добавить проверки Manager.IsIntelliSenseMode, так чтобы директива вообще не работала во IDE.

Ну, а там ты увидишь заработал ли комплит или нет. Если заработал, то твоя теория верна и можно думать дальше. Если нет, то придется копать в другом направлении.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Некорректная обработка директивы #line
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.04.10 16:04
Оценка:
Здравствуйте, seregaa, Вы писали:

S>Чет не могу предсавить примера. Но раз уж студия использует такой подход, думаю она знает что делает )


Ну, скажем у нас есть два фрагмента в одной строке:
ля ля ля <%: SomeFunc(...) %> ля <%: SomeFunc(...) %>

Код в обоих фрагментах нужно ведь обернуть в некий Write(). Если они подставляют пробелы, то не ясно как они на место " ля " смогут вписать другой код.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 18:08
Оценка:
Здравствуйте, VladD2, Вы писали:

S>>Вот вкратце как работает автодополнение для обычных файлов (мое сегодняшнее понимание процесса):

VD>А это понимание основано на чем? Предположения? Или это изучение вопроса под отладчиком и Рефлектором?
msdn, рефлектор, отладчик исходников .net и исходников интеграции железного питона

вот информация из msdn:
Contained languages are languages that are contained by other languages. You may need to implement contained languages to…For example, HTML in ASP.NET Web pages may contain Visual C# or Visual Basic scripts. A dual-language architecture is required for the .aspx file editor to provide IntelliSense, colorization, and other editing features for both the HTML and the scripting language.

Implementation Process
The most important interface you need to implement contained languages is the IVsContainedLanguage interface. This interface is implemented by any language that can be hosted inside a primary language. This interface gives access to the language service’s colorizer, text view filter, and primary language service ID. The IVsContainedLanguageFactory interface is implemented by a language that can be hosted as a contained language. This implementation enables you to create an IVsContainedLanguage interface. The following steps show you the process of implementing a contained language:

The developer implements QueryService() to query globally for the language service ID and the interface ID of the IVsContainedLanguageFactory.

The developer calls the GetLanguage method to create an IVsContainedLanguage interface. The GetLanguage method that you use to create an IVsContainedLanguage method requires an IVsHierarchy interface, an item ID that consists of one or more of the VSITEMID_NIL, VSITEMID_ROOT, or VSITEMID_SELECTION fields and an IVsTextBufferCoordinator interface.

The IVsTextBufferCoordinator interface, which is the text buffer coordinator object, provides the basic text mapping services that are required to map locations in a primary file into the secondary language’s buffer.

For example, in a single .aspx file, the primary file includes the ASP, HTML and all the code that is contained. However, the secondary buffer, includes just the contained code, together with any class definitions, to make the secondary buffer a valid code file. The buffer coordinator handles the work of coordinating edits from one buffer to the other.

The SetSpanMappings method, which is the primary language, tells the buffer coordinator what text within its buffer is mapped to corresponding text in the secondary buffer.

The language passes in an array of the NewSpanMapping structure, which currently only includes a primary and a secondary span.

The MapPrimaryToSecondarySpan method and the MapSecondaryToPrimarySpan method provide the mapping from primary to secondary buffer and vice versa.

http://msdn.microsoft.com/en-us/library/bb166334(VS.80).aspx

в принципе это все, что в MSDN есть на эту тему.

S>>Как только *.n файл открывается в редакторе, для него создается объект NemerleSource, обеспечивающий поддержку интеллисенса.

VD>Начнем с того, что этот файл, скорее всего не подключен ни к какому проекту. Стало быть получить по нему интелисенс для немерла будет наивозможно.

Я имею ввиду файл, подключенный к проекту. Как только он открывается в редакторе, для него создается NemerleSource. До этого для файла, включенного в проект, существует только FileNemerleSource, который реализует ограниченный функционал, а для получения содержимого файла использует чтение с диска.

S>>Этот объект обрабатывает запросы на автодополнение, отображение хинтов, а также события редактирования файла.

VD>А при редактировании все содержимое изменяется, или только участок файла соответствующий?

Влад, в первой части я описываю, как студия и интеграция обрабатывают обычные *.n файлы, подключенные к проекту. Думаю, ты и сам представляешь, что там внури при этом происходит. Я про очереди релокации и т.д.

S>>Для доступа к содержимому файла используется буфер, передаваемый в конструктор NemerleSource. Это позволяет всегда иметь дело с самым свежим содержимым файла, даже еще не сохраненным на диск.

VD>В принципе грамотно. Если они сделали пренаправление качественно, то можно попробовать это дело поддерживать.

Что поддерживать? Чтение из буфера используется интеграцией Немерле наверное с самого начала. В UpdateCompileUnit текст для парсинга получается следующей функцией:
public TupleStringIntInt NemerleSource::GetTextCurrentVersionAndFileIndex()
{
LockWrite();
try { return new TupleStringIntInt(GetText(), CurrentVersion, FileIndex); }
finally { UnlockWrite(); }
}

где GetText() — функция, читающая содержимое _буфера_.


S>>При каждом редактировании файла запускается процесс обновления объектной модели кода CompileUnit. Эта модель используется методами поддержки интеллисенса.

VD>Вот этого я не понял. Что и кем запускается? Это уже должна делать наша интеграция (наш код)... как реакция на изменение исходника (на событие изменения).

Да, эту часть делает наша интеграция. Я описывал процесс в комплексе.


S>>А вот как это работает для aspx файлов:

S>>Как только aspx файл открывается в редакторе, для него тоже создается NemerleSource, хотя aspx файл по сути не является корректным исходником на Немерле.
VD>А если aspx закрыт, исходника нет?

Да, пока он закрыт, исходника нет.

S>>Виртуальный исходник генерится так: инфраструктура asp.net парсит aspx файл и создает независимую от языка объектную модель кода страницы, которая затем переводится в код с помощью конкретного генератора, в нашем случае это NemerleCodeGenerator. Объектная модель содержит ссылки на aspx файл в виде элементов CodeLinePragma, который генератор Немерле генерирует как директивы #line.


VD>Это все ясно и не так интересно. Больше интересен сам процесс создания этого исходника.

VD>Этот исходник нужно как-то отловить, понять что он относится к проекту и кодключить его к этому самому проекту. Ну, а если исходник закрывается, то его нужно отключить от проекта.

Это я уже реализовал по образу и подобию питона — подключаю этот NemerleSource к проекту и отключаю после закрытия.

VD>Если же этот исходник всегда присутствует на диске и подключен к проекту (а как без этого его скомпилировать иначе?), то вопрос решается сам собой.


Нет, в дизайнтайме исходник существует только в буфере NemerleSource. Этот NemerleSource я временно подключаю к проекту (писал об этом выше). Для компиляции наличие файла необязательно.

S>>Затем содержимое вторичного буфера парсится с помощью простейшего парсера и обнаруженные блоки #line сопоставляются с <%%> блоками. Эта информация в дальнейшем используется для трансляции локаций первичного буфера в локации вторичного и наоборот.

VD>Этого не понял. Что за "обнаруженные блоки #line"? Зачем их обнаруживать? Они же просто в исходник помещаются (генерируемый).

Смотри. Студия генерит модель кода страницы (CodeDom). Генератор Немерле превращает модель в исходник. Затем наш код интеграции должен пройтись по сгенерированному исходнику, найти все блоки #line и сообщить об их расположении дизайнеру, чтобы дизайнер знал на какие участки кода маппировать блоки <%%>. Дизайнер не может сам пройтись по исходнику, потому что CodeLinePragma на разных языках может выглядеть по разному, VB.NEТ например, вместо #line использует директиву #ExternalSource. #line — это вообще то c# специфик директива, просто в Немерле решили не придумывать свой синтаксис, а заимствовали его у шарпа.

S>>Вторичный (сгенерированный) буфер и передается в конструктор NemerleSource. При этом запросы от редактора, открытого для первичного буфера (aspx), поступают в NemerleSource, созданный по вторичному буферу, транслируясь по пути из одной системы кординат в другую. Т.е. если нажать в aspx редакторе в строке 10 позиции 5 клавишу ".", то NemerleSource получит сигнал OnCommand с пересчитаными координатами, например 78 и 8.

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

Уже попробовал и убедился в успешной работе автокомплита.

S>>Для того, чтобы вся эта махина заработала, нужно уметь сопоставлять блоки в сгенерироанном коде и исходные <%%> блоки aspx файла. Поэтому отказаться от директивы #line не получится. А с директивами line не работает поиск выражений по координатам, поскольку локации выражений внутри блоков line имеют некорректные значения.

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

VD>Так что просто залезь в Lexer.n. Находи там строку 1464. Там расположен код обработки этой директив:

VD>В него надо добавить проверки Manager.IsIntelliSenseMode, так чтобы директива вообще не работала во IDE.

VD>Ну, а там ты увидишь заработал ли комплит или нет. Если заработал, то твоя теория верна и можно думать дальше. Если нет, то придется копать в другом направлении.


Схема работает, можно думать дальше )
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[9]: Некорректная обработка директивы #line
От: hardcase Пират http://nemerle.org
Дата: 27.04.10 18:19
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, seregaa, Вы писали:


S>>Чет не могу предсавить примера. Но раз уж студия использует такой подход, думаю она знает что делает )


VD>Ну, скажем у нас есть два фрагмента в одной строке:

VD>
VD>ля ля ля <%: SomeFunc(...) %> ля <%: SomeFunc(...) %>
VD>

VD>Код в обоих фрагментах нужно ведь обернуть в некий Write(). Если они подставляют пробелы, то не ясно как они на место " ля " смогут вписать другой код.

Позволю себе предположить:

До:
ля ля ля <%: SomeFunc(...) %> ля <%: SomeFunc(...) %>    // номер строки - L

После:
#line L - 1
Write(
             SomeFunc(...));
#line default

#line L - 1
Write(
                                     SomeFunc(...));
#line default
/* иЗвиНите зА неРовнЫй поЧерК */
Re[5]: Некорректная обработка директивы #line
От: hardcase Пират http://nemerle.org
Дата: 27.04.10 18:32
Оценка:
Здравствуйте, seregaa, Вы писали:

А вообще вся эта хитрозамученная механика с #line и ASPX сильно похожа на провал дизайна.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[10]: Некорректная обработка директивы #line
От: seregaa Ниоткуда http://blogtani.ru
Дата: 27.04.10 18:34
Оценка:
Здравствуйте, hardcase, Вы писали:

VD>>Ну, скажем у нас есть два фрагмента в одной строке:

VD>>
VD>>ля ля ля <%: SomeFunc(...) %> ля <%: SomeFunc(...) %>
VD>>

VD>>Код в обоих фрагментах нужно ведь обернуть в некий Write(). Если они подставляют пробелы, то не ясно как они на место " ля " смогут вписать другой код.
H>Позволю себе предположить:

так и есть. вот сгенерированный код:

        private __Renderform1 (__w : System.Web.UI.HtmlTextWriter,  parameterContainer : System.Web.UI.Control) : void
        {
            __w.Write("\r\n    <div>\r\nля ля ля ");
            
            #line 9 "C:\Users\Sergey\Documents\Visual Studio 2008\Projects\WebApplication19\WebApplication19\Default.aspx"
           : SomeFunc(...) 
            #line default
            __w.Write(" ля ");
            
            #line 9 "C:\Users\Sergey\Documents\Visual Studio 2008\Projects\WebApplication19\WebApplication19\Default.aspx"
                                   : SomeFunc(...) 
            #line default
            __w.Write("\r\n \r\n    </div>\r\n    ");
        }
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.