|
Lazarus IDE 工具
概述
IDE 使用了一个pascal 源代码语法分析和编辑工具的库, 叫 "codetools". 这些工具提供了如 查找声明(find declaration),代码完成 (code completion), 提取(extraction), 移动 插入 和 修饰 pascal 源代码的特性. 这些工具为你节省了时间提高了效率. 它们的很多特性是可定制的(see Editor Options).
因为它们仅工作在源代码上并理解 fpc, delphi 和 kylix 代码, 所以它们不需要编译的单元和一个 Borland 编译器. 你能同时编辑 Delphi 和 FPC 代码. 你也可以同时和不同版本的 Delphi 和 FPC 工作. 这使移植 Delphi 代码更简单.
IDE 快捷方式摘要表
跳到声明(Declaration Jumping) Ctrl+Click 或 Alt+Up (跳到类型和变量声明)
跳到方法(Method Jumping) Ctrl+Shift+Up (定义 和 主体间切换)
代码模版(Code Templates) Ctrl+J
代码完成 (类完成) Ctrl+Shift+C
标示符完成 Ctrl+Space
词完成 Ctrl+W
参数提示 Ctrl+Shift+Space
跳到方法
在一个过程体 (begin..end) 和 过程定义之间跳转 (procedure Name;) 用 Ctrl+Shift+Up.
例如:
interface
procedure DoSomething; // 过程定义
implementation
procedure DoSomething; // 过程体
begin
end;
如果光标在过程体上并且你按了 Ctrl+Shift+Up, 光标会跳到定义. 再次按 Ctrl+Shift+Up 又跳到过程体, 'begin'之后.
同样也适用于方法 (类中的过程).
提示: '跳到方法' 跳到同名和同参数列表的方法. 如果没有准确的方法, 它会跳到最佳候选并将光标放在第一个不同之处. (对于 Delphians: Delphi 不能做这个).
例如不同参数的过程:
interface
procedure DoSomething(p: char); // procedure definition
implementation
procedure DoSomething(p: string); // procedure body
begin
end;
从定义跳到体会将光标放在 'string' 关键字. 这可以用在重命名方法 和/或 改变了参数.
例如:
你重命名 'DoSomething' 为 'MakeIt':
interface
procedure MakeIt; // 过程定义
implementation
procedure DoSomething; // 过程体
begin
end;
然后你从MakeIt定义跳到过程体. IDE 搜索一个合适的过程体, 没找到, 因此搜索到一个候补 你只改变了过程名 留下一个没有定义的过程体 (DoSomething) 因此它跳到 DoSomething 并将光标放在 'DoSomething'右边. 然后你可以方便的重命名它. 这也同样适用于参数
包含文件
包含文件是插入到源代码中的 {$I filename} 或 {$INCLUDE filename} 编译器指令中的文件. Lazarus 和 FPC使用这些来减少代码冗余并使代码易读 {$IFDEF} 构造来支持不同的平台.
与Delphi相反, Lazarus IDE 完全支持保护文件. 例如你能从 .pas 文件的一个方法跳到包含文件中的方法体. 所有的代码工具像代码完成 将包含文件作为特殊的边界(bounds).
举例: 当代码完成添加一个新的方法体到另一个方法体后面, 它会在同一个文件中维护它们. 用这种方法你可以把整个类的实现在放在包含文件中, 像 LCL 这样做了几乎所有的控件.
但这也有缺点: 如果你首先打开一个包含文件并用跳到方法或寻找定义 你会得到一个错误. IDE 不知道这个包含文件属于哪个单元. 你必须先打开单元.
在IDE分析单元语法的同时,它也分析包含指令 同时 IDE 会记住这些关系. 在退出时保存这些项目信息到文件 ~/.lazarus/includelinks.xml.下次你开打这些包含文件并跳或寻找声明, IDE 会自动打开单元并跳去.
这个原理当然也有限制. 一些包含文件被包含了两次或更多. 比如: lcl/include/winapih.inc.
从包含文件中的过程/方法跳到体取决于你最后的动作. 如果你用了 lcl/lclintf.pp IDE 会跳到 winapi.inc.如果你用了 lcl/interfacebase.pp, 它会跳到 lcl/include/interfacebase.inc (或其他包含文件). 如果你两个都用了, 那你会被拒绝. ;)
Code Templates
代码模版转换一个标示符到一个文本或代码片段.
代码模版的快捷方式是 Ctrl+J. 你键入一个标示符, 按下 Ctrl+J 会被标示符所定义的文本替换. 代码模版在 Environment -> Editor Options -> CodeTools中定义.
例如: 键入标示符 'classf', 光标在 'f'右边 并按下 Ctrl+J. 'classf' 会被下面代码替换
T = class(T)
private
public
constructor Create;
destructor Destroy; override;
end;
光标在 'T'后面. 你能得到模版列表 将光标放在空白处(不要在标示符上) 并按下 Ctrl+J. 代码模版列表就会弹出. 用光标键或键入一些字符来选择一个. 回车选择模版创建 Escape 关闭弹出.
节省最大的时间是 'b'+Ctrl+J 来 begin..end.
参数提示
参数提示显示一个参数列表的提示框.
例如
Canvas.FillRect(|);
把光标放在括号中并按下 Ctrl+Shift+Space. 一个提示框会显示 FillRect的参数列表.
代码完成
代码完成在 IDE 菜单 Edit -> Complete Code 有标准快捷方式 Ctrl+Shift+C.
对于Delphians: Delphi 调用 "code completion" 功能在当前源代码位置显示标示符列表 (Ctrl+Space). 在 Lazarus中 这叫 "Identifier completion".
代码完成组合了几个强大的功能. 比如:
* 类完成: 完成属性, 添加方法体, 添加私有变量 和 私有方法
* 向前的方法完成: 添加方法体
* 事件赋值完成: 完成事件的赋值并添加方法定义和方法体
* 变量宣告完成: 添加局部变量定义
* 过程调用完成: 添加一个新的过程
* 反向过程完成: 为 过程/函数体添加过程定义
* 反向类完成: 为方法体添加方法定义
用哪一个功能, 取决于光标在编辑器中的位置.
类完成
最强大的代码完成特性是 "类完成". 你写一个类, 添加方法和熟悉 代码完成会添加方法体, 属性存取 方法/变量 和私有变量.
例如: 建一个类 (see Code Templates to save you some type work):
TExample = class(TObject)
public
constructor Create;
destructor Destroy; override;
end;
把光标放在类的某处并按下 Ctrl+Shift+C. 这会创建方法体并将光标移到第一个创建的方法体, 因此你只用写类的代码:
{ TExample }
constructor TExample.Create;
begin
|
end;
destructor TExample.Destroy;
begin
inherited Destroy;
end;
主要: '|' 是光标而不是添加的.
提示:你可以用 Ctrl+Shift+Up在方法和方法体之间跳转.
你可以看到, IDE 添加 'inherited Destroy' 调用. 如果有一个 'override' 关键字在类的定义, 他就这么做.
现在添加一个 DoSomething方法:
TExample = class(TObject)
public
constructor Create;
procedure DoSomething(i: integer);
destructor Destroy; override;
end;
按下Ctrl+Shift+C IDE 会添加
procedure TExample.DoSomething(i: integer);
begin
|
end;
你可以看到, 新的方法体被插入到 Create 和 Destroy之间, 正如类的定义. 这样方法体保持和定义一样的逻辑排序. 你可以定义插入方法在 Environment > Codetools Options -> Code Creation.
完成属性
添加一个AnInteger属性:
TExample = class(TObject)
public
constructor Create;
procedure DoSomething(i: integer);
destructor Destroy; override;
property AnInteger: Integer;
end;
按下 Ctrl+Shift+C 你会得到:
procedure TExample.SetAnInteger(const AValue: integer);
begin
|if FAnInteger=AValue then exit;
FAnInteger:=AValue;
end;
代码完成会添加一个写存取修饰符和一些代码. 用 Ctrl+Shift+Up跳到类看看新的类:
TExample = class(TObject)
private
FAnInteger: integer;
procedure SetAnInteger(const AValue: integer);
public
constructor Create;
procedure DoSomething(i: integer);
destructor Destroy; override;
property AnInteger: integer read FAnInteger write SetAnInteger;
end;
属性被读和写存取修饰符扩展了. 类得到新的变量 'FAnInteger'在 'private'区 和新的方法'SetAnInteger'. 这是Delphi 风格 用 'F'修饰私有变量 'Set'修饰写方法.如果你不喜欢, 你可以在 Environment > Codetools Options -> Code Creation中改变.
创建一个只读属性:
property PropName: PropType read;
被扩展成
property PropName: PropType read FPropName;
创建一个只写属性:
property PropName: PropType write;
被扩展成
property PropName: PropType write SetPropName;
用一个读方法创建一个只读属性:
property PropName: PropType read GetPropName;
GetPropName 会被添加:
function GetpropName: PropType;
用stored 修饰符创建一个属性:
property PropName: PropType stored;
被扩展成
property PropName: PropType read FPropName write SetPropName stored PropNameIsStored;
因为 stored 用来自动被流读写.
提示: 标示符完成 也可以认出未完成的属性并建议默认的名字. 例如:
property PropName: PropType read |;
将光标放在 'read' 关键字后 按下 Ctrl+Space 调用标示符完成. 它会给出变量 'FPropName' 和过程 'SetPropName'.
向前的过程完成
"向前的过程完成" 是代码完成的一部分 添加缺失的过程体.当光标在一个向前的过程定义,它会被调用.
例如: 添加一个新的过程在 interface 节:
procedure DoSomething;
把光标放在上面按下 Ctrl+Shift+C 调用代码完成. 它会创建一个 implementation 节:
procedure DoSomething;
begin
|
end;
提示: 你可以用 Ctrl+Shift+Up在过程定义和过程体之间跳转.
新的过程体会被添加到类方法前面. 如果 interface 已存在一些方法IDE 会保持它的排序. 例如:
procedure Proc1;
procedure Proc2; // new proc
procedure Proc3;
如果 Proc1 和 Proc3 过程体都存在, 那么Proc2 过程体会被插入到 Proc1 和 Proc3之间.这个特性可以在 Environment > Codetools Options -> Code Creation设置.
多个过程:
procedure Proc1_Old; // 函数体存在
procedure Proc2_New; // 函数体不存在
procedure Proc3_New; // "
procedure Proc4_New; // "
procedure Proc5_Old; // 函数体存在
代码完成会添加三个过程体 (Proc2_New, Proc3_New, Proc4_New).
为什么叫它 "向前的过程完成"?
因为它不只是为interface定义的过程工作, 也为 "forward" 修饰的过程. 还因为代码工具处理interface的过程作为暗含 'forward' 修饰符.
事件赋值完成
"事件赋值完成" 是代码完成的一部分并完成一个单独的 Event:=| 语句. 当光标在一个事件的赋值后, 它会被调用.
例如: 在一个方法中, 叫 FormCreate 事件, 添加一行 'OnPaint:=':
procedure TForm1.Form1Create(Sender: TObject);
begin
OnPaint:=|
end;
'|' 是光标不是键入的. 按下Ctrl+Shift+C 调用代码完成. 语句会自动完成
OnPaint:=@Form1Paint;
一个新的方法 Form1Paint 会被添加到 TForm1 类. 类的completion 开始得到:
procedure TForm1.Form1Paint(Sender: TObject);
begin
|
end;
这个工作就像在对象检查器中添加方法.
注意:
你必须将光标放在 ':=' 赋值操作符后. 如果你把光标放在标示符 (e.g. OnPaint) 代码完成会调用 "局部变量完成", 并失败, 因为 OnPaint已定义了.
提示:
你可以自己定义方法名. 比如:
OnPaint:=@ThePaintMethod;
变量宣告完成
"变量宣告完成" 是代码完成的一部分 添加一个局部变量定义为 Identifier:=Term; 语句. 当光标在一个赋值或参数的标示符上时,它被调用.
比如:
procedure TForm1.Form1Create(Sender: TObject);
begin
i:=3;
end;
将光标放在 'i' 上或后.按下 Ctrl+Shift+C 调用代码完成你会得到:
procedure TForm1.Form1Create(Sender: TObject);
var
i: Integer;
begin
i:=3;
end;
代码工具首先检查, 标示符 'i' 是否已经定义如果没有就添加声明 'var i: integer;'. 标示符的种类由赋值号 ':=' 右边的项猜出. 数字 3 默认为整数.
另一个例子:
type
TWhere = (Behind, Middle, InFront);
procedure TForm1.Form1Create(Sender: TObject);
var
a: array[TWhere] of char;
begin
for Where:=Low(a) to High(a) do writeln(a[Where]);
end;
把光标放在 'Where' 按下 Ctrl+Shift+C 调用代码完成. 你会得到:
procedure TForm1.Form1Create(Sender: TObject);
var
a: array[TWhere] of char;
Where: TWhere;
begin
for Where:=Low(a) to High(a) do writeln(a[Where]);
end;
自 0.9.11 后Lazarus 也完成参数. 例如
procedure TForm1.FormPaint(Sender: TObject);
begin
with Canvas do begin
Line(x1,y1,x2,y2);
end;
end;
光标放在 'x1' 按下 Ctrl+Shift+C 调用代码完成. 你会得到:
procedure TForm1.FormPaint(Sender: TObject);
var
x1: integer;
begin
with Canvas do begin
Line(x1,y1,x2,y2);
end;
end;
过程调用完成
代码完成可以从调用语句创建一个新的过程 .
假如你写了一个语句"DoSomething(Width);"
procedure SomeProcedure;
var
Width: integer;
begin
Width:=3;
DoSomething(Width);
end;
光标放在 "DoSomething" 上按下 Ctrl+Shift+C 将得到:
procedure DoSomething(aWidth: LongInt);
begin
end;
procedure SomeProcedure;
var
Width: integer;
begin
Width:=3;
DoSomething(Width);
end;
还不可以创建函数和方法.
反向类完成
"反向类完成"是代码完成的一部分它为当前的方法体添加一个私有的方法声明. 当光标在一个方法体, 而方法没有在类中定义, 它会被调用. 这个特性从 Lazarus 0.9.21开始.
例如:
procedure TForm1.DoSomething(Sender: TObject);
begin
end;
方法 DoSomething还没有在 TForm1中定义. 按下 Ctrl+Shift+C IDE 会添加 "procedure DoSomething(Sender: TObject);" 给TForm1的私有方法.
对于Delphians: Lazarus的类完成只有一种方法:从类的 interface 到 implementation 或 向后/相反与类 implementation 到 interface. Delphi 总是调用两个方向. Delphi 的方式有缺陷, 排版时没注意会简单的创建一个新的方法存根.
注释和代码完成
代码完成会保留它们的注释. 比如:
FList: TList; // list of TComponent
FInt: integer;
当在FList 和 FInt之间插入新的变量,注释保留在 FList 行. 同样对于
FList: TList; { list of TComponent
This is a comment over several lines, starting
in the FList line, so codetools assumes it belongs
to the FLIst line and will not break this
relationship. Code is inserted behind the comment. }
FInt: integer;
如果注释开始于下一行, 它会被处理为属于下面. 例如:
FList: TList; // list of TComponent
{ 这个注释属于下面的语句.
新代码会插入到这个注释上面 并在 FList 行注释的后面. }
FInt: integer;
重新排列
反转赋值
摘要: "反转赋值" 把所选的 pascal 语句 并反转所有的赋值. 这个工具对于把 "save" 代码转为 "load" 或相反的操作很有用.
例如:
procedure DoSomething;
begin
AValueStudio:= BValueStudio;
AValueAppartment :=BValueAppartment;
AValueHouse:=BValueHouse;
end;
选择赋值语句行( begin 和 end之间) 并反转赋值. 所有的赋值语句被反转并自动添加标示符. 例如:
结果:
procedure DoSomething;
begin
BValueStudio := AValueStudio;
BValueAppartment := AValueAppartment;
BValueHouse := AValueHouse;
end;
装入所选
选择一些文本并调用它. 弹出一个对话框让你选择是否将所选装入try..finally 或 其他的块.
重命名标示符
把光标放在标示符上并调用它. 将显示一个对话框, 你可以设置搜索范围和新的名字.
* 它会重命名所有这个声明的引用. 意思是它不重命名声明.
* 它会先检查名字冲突.
* 限制: 只在pascal 源代码上工作, 还不能重命名 lfm/lrs 文件 和 lazdoc files.
查找标示符引用
把光标放在标示符上并调用. 将显示一个对话框, 你可以设置搜索范围. IDE 会搜索所有的用这个声明存在的引用. 意思是不显示其他同名声明.
显示抽象方法
这个特性列出并自动完成需要实现的 virtual, abstracts 方法. 光标放在类的声明并调用它.如果有缺失的 abstract 方法 一个对话框会列出它们. 选择方法来实现 IDE 创建方法的存根.
提取过程
See Extract Procedure
寻找声明
光标放在标示符上并 '寻找声明'. 它会寻找这个标示符的声明, 打开文件并跳到它.
所有的寻找声明设置了一个跳入点. 意思是你用寻找声明跳入声明并可以简单的跳回 Search -> Jump back.
这和 Delphi有些不同: 代码工具在源代码上工作 遵循一个 pascal 规则, 代替使用编译器输出. 编译器返回最终类型. 代码工具查看源代码 和 所有步骤之间.例如:
Visible属性首先在 TControl (controls.pp)定义, 然后在 TCustomForm 重新定义又在 TForm中重新定义.调用寻找Visible声明会带你到TForm的Visible. 然后你可以再次调用寻找声明跳到 TCustomForm的Visible再一次就跳到 TControl的Visible.
同样适用于 TColor类型. 对编译器来说它是一个简单的 'longint'. 但在源代码中他被定义为
TGraphicsColor = -$7FFFFFFF-1..$7FFFFFFF;
TColor = TGraphicsColor;
同样适用于向前定义的类: TControl 的实例, 有私有变量
FHostDockSite: TWinControl;
在 TWinControl寻找声明 跳到向前的定义
TWinControl = class;
再次调用就跳到真正的实现
TWinControl = class(TControl)
这样你可以跟踪每一个标示符 并找到每一个重载.
提示: 你可以用 Ctrl+H跳回.
标示符完成
"标示符完成" 用 Ctrl+Space调用. 它显示范围内的所有标示符.例如:
procedure TForm1.FormCreate(Sender: TObject);
begin
|
end;
光标在begin 和 end 之间按下 Ctrl+Space. IDE/代码工具 会分析所有可达的代码并列出找到的标示符. 代码工具将结果缓冲, 因此第二次调用会更快.
对于Delphians要注意: Delphi 叫代码完成.
一些标示符如'Write', 'ReadLn', 'Low', 'SetLength', 'Self', 'Result', 'Copy'是编译器内建的不可以用来定义. 标示符完成也适用于这些内建的. 如果你没有找到想要的,在臭虫跟踪者(bug tracker)中创建一个特性要求 .
标示符完成不完成关键字. 因此你不能完成 'proc' 到'procedure'. 用 Ctrl+W 词完成代替 Ctrl+J 代码完成来完成.
标示符完成甚至显示不兼容的标示符.
前缀
你可以用标示符完成. 把左边的字符作为前缀. 例如:
procedure TForm1.FormCreate(Sender: TObject);
begin
Ca|ption
end;
会显示 'Ca'开头的标示符.
按键
* 字母或数字: 添加字符到编辑器和当前前缀. 这会更新列表.
* 退格: 从编辑器和前缀删除最后一个字母. 更新列表.
* 回车: 用所选的标示符替换光标下的单词并关闭弹窗.
* Shift+回车: 返回,但只替换光标下单词前缀 (左边部分) .
* 上/下: 移动所选
* Escape: 关闭弹窗
* Tab: 完成前缀到下一个选择. 例如: 当前前缀是 'But' 并且标示符完成只显示 'Button1' 和 'Button1Click'. 按下 Tab 完成前缀为 'Button1'.
* 其他: 返回并添加到编辑器
方法
光标在类定义中 在父类中用标示符完成一个方法参数和重载关键字定义. 例如:
TMainForm = class(TForm)
protected
mous|
end;
完成 MouseDown 给出:
TMainForm = class(TForm)
protected
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer); override;
end;
属性
property MyInt: integer read |;
标示符完成显示 FMyInt 和 GetMyInt.
property MyInt: integer write |;
标示符完成显示 FMyInt 和 SetMyInt.
Uses section / Unit 名字
在 uses 节 标示符完成显示可搜索到的路径中所有单元的文件名. 显示小写 (e.g. avl_tree), 因为大多数单元都是小写的文件名. 在 completion 节它会给出单元的最佳情况 (e.g. AVL_Tree).
语句
procedure TMainForm.Button1Click(Sender: TObject);
begin
ModalRe|;
end;
变成:
procedure TMainForm.Button1Click(Sender: TObject);
begin
ModalResult:=|;
end;
词完成
"词完成" 用 Ctrl+W调用. 显示当前编辑器的所有单词.
否则和标示符完成一样.
到包含指令
"到包含指令" 在 IDE的搜索菜单跳到 {$I filename} 当前用到的包含文件语句 .
发布项目
建立项目的副本. 如果你想给其他人源代码和编译器配置,这个功能很好用.
一个项目文件夹包含了许多信息. 他们的大多数不需要发布: .lpi 文件含有会话信息 (如 ^的位置和相关单元的标签)项目文件夹包含一些 .ppu, .o 文件和可执行文件.要用基本信息和源代码创建 lpi 文件, 同所有子目录一起用 " ublish Project".
注意: 从 0.9.13 版开始有一个新的项目选项允许你存储节信息到分开的文件从一般的 .lpi 文件. 这个新文件以 .lps 为扩展名并只包含节信息, 可以使你的 .lpi 文件更干净.
对话框中你可以设置排除和包含过滤器, 并压缩输出到一个文件. |
评分
-
查看全部评分
|