Web-разработка, иностранные языки, Eclipse и разные разности

Zygo Profile

Санскрит - словоформы

Verbos Irregulares

Eclipse

9. Поддержка переменных.

09.11.2015
Давайте продолжим работу над нашим маленьким примером отладчика и добавим в него отображение переменных.

Шаг 1. Реализация классов переменных.


Переменные привяжутся к кадрам стека (StackFrames) и будут запрошены только в тот момент, когда отладчик будет приостановлен. Чтобы реализовать их, нам нужно описание переменных, сохраненное в TextVariable:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.codeandme.textinterpreter.debugger.model;  
  
public class TextVariable extends TextDebugElement implements IVariable {  
  
 private final String mName;  
 private IValue mValue;  
  
 protected TextVariable(IDebugTarget target, String name, String value) {  
  super(target);  
  mName = name;  
  setValue(value);  
 }  
  
 @Override  
 public void setValue(String expression) {  
  mValue = new TextValue(getDebugTarget(), expression);  
 }  
  
 @Override  
 public void setValue(IValue value) {  
  mValue = value;  
 }  
  
 @Override  
 public boolean supportsValueModification() {  
  return false;  
 }  
  
 @Override  
 public boolean verifyValue(String expression) throws DebugException {  
  return false;  
 }  
  
 @Override  
 public boolean verifyValue(IValue value) throws DebugException {  
  return false;  
 }  
  
 @Override  
 public IValue getValue() {  
  return mValue;  
 }  
  
 @Override  
 public String getName() {  
  return mName;  
 }  
  
 @Override  
 public String getReferenceTypeName() throws DebugException {  
  return "text type";  
 }  
  
 @Override  
 public boolean hasValueChanged() throws DebugException {  
  return false;  
 }  
}  


Реализация достаточно проста и не позволяет модифицировать содержимое переменных.
Дальше >>

8. Добавляем поддержку "Перехода на строку" (Run to line)

08.11.2015
Специализированную поддержку перехода на строку осуществить достаточно просто. Большая часть обеспечивается фреймворком отладчика, все что нам нужно, это правильно воспользоваться этим.

Шаг 1. Осуществление поддержки редактора.


Чтобы использовать функционал перехода на строку из фреймворка отладчика, редактор исходного кода должен осуществлять интерфейс IRunToLineTarget.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.codeandme.textinterpreter.debugger;  
  
public class RunToLineTarget implements IRunToLineTarget {  
  
 @Override  
 public void runToLine(IWorkbenchPart part, ISelection selection, ISuspendResume target) throws CoreException {  
  if (target instanceof TextStackFrame) {  
   IDebugTarget debugTarget = (IDebugTarget) ((IAdaptable) target).getAdapter(IDebugTarget.class);  
   if (debugTarget instanceof TextDebugTarget) {  
    IBreakpoint breakpoint = new TextRunToLineBreakpoint(((TextDebugTarget) debugTarget).getFile(), getLineNumber(selection));  
    RunToLineHandler handler = new RunToLineHandler(debugTarget, target, breakpoint);  
    handler.run(new NullProgressMonitor());  
   }  
  }  
 }  
  
 @Override  
 public boolean canRunToLine(IWorkbenchPart part, ISelection selection, ISuspendResume target) {  
  return (target instanceof TextStackFrame);  
 }  
  
 private static int getLineNumber(ISelection selection) {  
  if (selection instanceof ITextSelection)  
   // text selections are 0 based  
   return ((ITextSelection) selection).getStartLine() + 1;  
  
  return 0;  
 }  
}  


В вызове runToLine() мы создаем новый  TextRunToLineBreakpoint, автоматически активируемый разработчиком. Единственное отличие от TextLineBreakpoint заключается в том, что мы устанавливаем его флаг PERSISTED в false.

Реализация отладочного фреймворка так же учитывает установки предпочтений точек останова Run/Debug / Skip в течение обработки 'Перехода на Строку'. Хотя мне такая реализация кажется немного некорректной. Поскольку демо-интерпретатор работает молниеносно, обычные точки останова временами не будут отключаться достаточно быстро и могут даже сработать.

Шаг 2. Регистрация интеграции UI.


Чтобы добавить действие (action) в контекстное меню редактора, нам нужно добавить новую точку расширения org.eclipse.ui.popupMenus. Добавьте viewerContribution с значением id равным "textEditor.editorActions" и targetID - "#TextEditorContext". Теперь добавьте действие перехода на строку (Run to line) таким образом, как показано на скриншоте



Кроме того, нам необходимо зарегистрировать адаптер для текстового редактора, поскольку он изначально не осуществляет интерфейс IRunToLineTarget. RunToLineAdapter всего лишь превращает редакторы в IRunToLineTargets.

7. Поиск исходника.

07.11.2015
Иметь поддержку пошагового прохода и исходного кода - замечательно, но пользователю необходима видимая обратная связь, чтобы понять, где отладчик временно приостановил работу. Исходный код должен быть открыт в редакторе и текущая строка должна быть подсвечена.

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

Шаг 1. Развернутая картина.


Когда поток отладчика начинает обработку, он обычно вызывает файлы, методы или функции. Такие элементы составляют стек вызовов. Фреймворк отладчика использует этот стек, чтобы установить текущее место в исходном коде. Каждый элемент стека может быть привязан к определенному месту исходника (содержимое редактора + выделение внутри редактора).



Интерфейс ISourceLocator прикрепляется к расширению запуска как правило посредством использования точки расширения org.eclipse.debug.core.sourceLocators. Локатор превращает IStackFrame в элемент исходника посредством getSourceElement(IStackFrame stackFrame). Этот элемент обычно запрашивает IEditorInput и editorID из отладочной модели. Теперь редактор можно открыть. Выделение строки находится из стекового кадра.

Дальше >>

6. Интеграция точек останова и отладчика

06.11.2015

После того, как мы уже реализовали возможность работы с точками останова из UI, нам нужно научить нашу модель отладчика (debug model) и отладчик их использовать.

Шаг 1. Добавление точек останова в модель.


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

Модель отладчика (debug model) может оказывать воздействие и устанавливать точки останова до того, как выполнение продолжится. Помимо того нам необходимо улавливать изменения, касающиеся точек останова, чтобы добавлять новые точки останова в отладчик или удалять их, когда они отключаются или удаляются пользователем.

Давайте начнем с реализации слушателя событий (listener):



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.codeandme.textinterpreter.debugger.model;  
  
public class TextDebugTarget extends TextDebugElement implements IDebugTarget, IEventProcessor {  
  
 @Override  
 public boolean supportsBreakpoint(final IBreakpoint breakpoint) {  
  if (mFile.equals(breakpoint.getMarker().getResource())) {  
   // breakpoint on our source file  
   return true;  
  }  
  
  return false;  
 }  
  
 private boolean isEnabledBreakpoint(IBreakpoint breakpoint) {  
  try {  
   return breakpoint.isEnabled() && DebugPlugin.getDefault().getBreakpointManager().isEnabled();  
  } catch (CoreException e) {  
   // ignore invalid breakpoint  
  }  
  
  return false;  
 }  
  
 // ************************************************************  
 // IBreakpointListener  
 // ************************************************************  
  
 @Override  
 public void breakpointAdded(final IBreakpoint breakpoint) {  
  if ((supportsBreakpoint(breakpoint)) && (isEnabledBreakpoint(breakpoint)))  
   fireModelEvent(new BreakpointRequest(breakpoint, BreakpointRequest.ADDED));  
 }  
  
 @Override  
 public void breakpointRemoved(final IBreakpoint breakpoint, final IMarkerDelta delta) {  
  if (supportsBreakpoint(breakpoint))  
   fireModelEvent(new BreakpointRequest(breakpoint, BreakpointRequest.REMOVED));  
 }  
  
 @Override  
 public void breakpointChanged(final IBreakpoint breakpoint, final IMarkerDelta delta) {  
  breakpointRemoved(breakpoint, delta);  
  breakpointAdded(breakpoint);  
 }  

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

Пока нет дальнейших проверок для удаления точек останова, мы добавляем только активные точки останова. Существует две различных возможности включения/отключения точек останова, которые нам надо проверить: может ли быть отключена сама точка останова и/или менеджер точек останова (BreakpointManager) может быть отключен глобально.

Сейчас нам необходимо позаботиться о том, что мы отслеживаем изменения, связанные в точках останова согласно тому, что указано в менеджере точек останова (BreakpointManager).



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.codeandme.textinterpreter.debugger.model;  
  
public class TextDebugTarget extends TextDebugElement implements IDebugTarget, IEventProcessor {  
  
 @Override  
 public void handleEvent(final IDebugEvent event) {  
  
  if (!isDisconnected()) {  
   System.out.println("Target.handleEvent() " + event);  
  
   if (event instanceof DebuggerStartedEvent) {  
    // create debug thread  
    TextThread thread = new TextThread(this);  
    mThreads.add(thread);  
    thread.fireCreationEvent();  
  
    // debugger got started and waits in suspended mode  
    setState(State.SUSPENDED);  
  
    // add breakpoint listener  
    DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);  
  
    // attach deferred breakpoints to debugger  
    IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(getModelIdentifier());  
    for (IBreakpoint breakpoint : breakpoints)  
     breakpointAdded(breakpoint);  
  
    // resume execution after setting breakpoints  
    resume();  
  
   [...]  
  
   } else if (event instanceof TerminatedEvent) {  
    // debugger is terminated  
    setState(State.TERMINATED);  
  
    // unregister breakpoint listener  
    DebugPlugin.getDefault().getBreakpointManager().removeBreakpointListener(this);  
  
    // we do not need our dispatcher anymore  
    mDispatcher.terminate();  
  
    // inform eclipse of terminated state  
    fireTerminateEvent();  
   }  
  }  
 }  
}  

В событии DebuggerStartedEvent нам необходимо указать все значимые точки останова. После чего мы сможем продолжить, поскольку нам будет доступна полная поддержка точек останова.

Шаг 2. Добавление поддержки точек останова в отладчик.


Нашему отладчику нужно закешировать точки останова и проверить их в событии изменения строки. В нашем случае мы будем только отслеживать номера строк, на которых мы хотим задержаться:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.codeandme.textinterpreter.debugger;  
  
public class TextDebugger implements IDebugger, IEventProcessor {  
  
 private final Set<integer> mBreakpoints = new HashSet<integer>();  
  
 @Override  
 public boolean isBreakpoint(final int lineNumber) {  
  if (mBreakpoints.contains(lineNumber))  
   return true;  
  
  return mIsStepping;  
 }  
  
 @Override  
 public void handleEvent(final IDebugEvent event) {  
  System.out.println("Debugger.handleEvent() " + event);  
  
  [...]  
  
  } else if (event instanceof BreakpointRequest) {  
   int line = ((BreakpointRequest) event).getBreakpoint().getMarker().getAttribute(IMarker.LINE_NUMBER, -1);  
   if (line != -1) {  
    if (((BreakpointRequest) event).getType() == BreakpointRequest.ADDED)  
     mBreakpoints.add(line);  
  
    else if (((BreakpointRequest) event).getType() == BreakpointRequest.REMOVED)  
     mBreakpoints.remove(line);  
   }  
  }  
 }  
}

Механизм установки и кеширования точек останова может быть немного более сложным в реальной жизни, поскольку вы имеете возможность поддерживать различные типы точек останова наподобие точек останова в функциях (function breakpoints) и контрольных точек (watchpoints).

5. UI интеграция точек останова.

05.11.2015

В предыдущей части руководства мы реализовали проход по исходному коду. Пошаговый проход - это здорово, но нам еще нужно добавить поддержку точек останова для улучшения качества отладки. В конце данного руководства мы сможем устанавливать их, используя UI:



В среде Эклипс существует несколько разновидностей точек останова:
точки останова на строке (line breakpoints) - остановка исполнения кода на определенной строке, точка останова на функции (function breakpoints) - останов происходит, когда вызывается некоторая функция foo(), контрольные точки (watchpoints) - останов происходит, когда определенная переменная используется в коде или изменяет свое значение. Не все из них имеют смысл, когда речь идет о каком-либо специализированном языке. В этом руководстве мы рассмотрим только точки останова на строке.

Дальше >>
Облако тегов
Меню
Архив
<< < 12 > >>
© Psytronica.ru. Блог существа SherZa. 2015-2017 Наверх