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

Zygo Profile

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

Verbos Irregulares

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;  
 }  
}  


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

Текущее значение сохранено в другом классе:


 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
package com.codeandme.textinterpreter.debugger.model;  
  
import org.eclipse.debug.core.DebugException;  
import org.eclipse.debug.core.model.IDebugTarget;  
import org.eclipse.debug.core.model.IValue;  
import org.eclipse.debug.core.model.IVariable;  
  
public class TextValue extends TextDebugElement implements IValue {  
  
 private final String mValue;  
  
 public TextValue(IDebugTarget target, String value) {  
  super(target);  
  
  mValue = value;  
 }  
  
 @Override  
 public String getReferenceTypeName() throws DebugException {  
  return "text type";  
 }  
  
 @Override  
 public String getValueString() throws DebugException {  
  return mValue;  
 }  
  
 @Override  
 public boolean isAllocated() throws DebugException {  
  return true;  
 }  
  
 @Override  
 public IVariable[] getVariables() throws DebugException {  
  return new IVariable[0];  
 }  
  
 @Override  
 public boolean hasVariables() throws DebugException {  
  return false;  
 }  
}  


Чтобы отобразить иерархические структуры, значение должно содержать дочерние переменные (напр. поля класса, элементы коллекции, ...). В этом случае вам так же необходимо реализовать hasVariables() и getVariables().

Вы могли обратить внимание, что оба класса определяют метод getReferenceTypeName(). В то время как TextVariable.getReferenceTypeName() обозначает объявленный тип переменной, Textvalue.getReferenceTypeName() обозначает фактический тип. Поглядите на java-пример:


1
IValue value = new TextValue();  


Объявленный тип будет IValue, в то время как реальный тип - TextValue. Вы можете включить эти колонки в debug view, открыв меню Variables view и выбрав Layout / Select Columns...

Шаг 2. Обновление переменных.


А сейчас важный вопрос: "Как и когда обновлять переменные"?

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

  1. Заполнить все стековые кадры автоматически по наступлению события временной приостановки на тот случай, чтобы наш пользователь мог запросить их.
  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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.codeandme.textinterpreter.debugger.model;  
  
public class TextStackFrame extends TextDebugElement implements IStackFrame {  
  
 private final List<TextVariable> mVariables = new ArrayList<TextVariable>();  
 private boolean mDirtyVariables = true;  
  
 @Override  
 public synchronized IVariable[] getVariables() {  
  if (mDirtyVariables) {  
   mDirtyVariables = false;  
   getDebugTarget().fireModelEvent(new FetchVariablesRequest());  
  }  
  
  return mVariables.toArray(new IVariable[mVariables.size()]);  
 }  
  
 public synchronized void setVariables(Map<String, String> variables) {  
  for (String name : variables.keySet()) {  
   boolean processed = false;  
   // try to find existing variable  
   for (TextVariable variable : mVariables) {  
    if (variable.getName().equals(name)) {  
     // variable exists  
     variable.setValue(variables.get(name));  
     variable.fireChangeEvent(DebugEvent.CONTENT);  
     processed = true;  
     break;  
    }  
   }  
  
   if (!processed) {  
    // not found, create new variable  
    TextVariable textVariable = new TextVariable(getDebugTarget(), name, variables.get(name));  
    mVariables.add(textVariable);  
    textVariable.fireCreationEvent();  
   }  
  }  
 }  
  
 @Override  
 public synchronized void fireChangeEvent(int detail) {  
  mDirtyVariables = true;  
  
  super.fireChangeEvent(detail);  
 }  
}  


TextDebugger отправляет свой список переменных посредством нового события  классу TextDebugTarget, который передает вызов в верхний StackFrame внутри метода  handleEvent(). В течение обновления мы отсылаем либо событие изменения или создания для обновленных переменных. Конечно, настоящая реализация должна была бы быть более осмысленной, чем реализованная выше версия и использовать разумное сравнение и кеширование.

Если вы хотите, чтобы измененный контент был подсвечен, вам стоит реализовать IVariable.hasValueChanged().



UI проблемы


Существует еще не исправленный мной момент: иногда Variables view может оставаться пустым, когда отладчик временно приостанавливается. Если убрать view назад, а затем снова вытащить вперед, проблема решается. У меня нет уверенности, является ли это проблемой моего кода или фреймворка отладчика.

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