⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dws2syneditutils.pas

📁 script language
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{**********************************************************************}
{                                                                      }
{    "The contents of this file are subject to the Mozilla Public      }
{    License Version 1.1 (the "License"); you may not use this         }
{    file except in compliance with the License. You may obtain        }
{    a copy of the License at                                          }
{                                                                      }
{    http://www.mozilla.org/MPL/                                       }
{                                                                      }
{    Software distributed under the License is distributed on an       }
{    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express       }
{    or implied. See the License for the specific language             }
{    governing rights and limitations under the License.               }
{                                                                      }
{    The Original Code is DWSUnitEditorUtils source code, released     }
{    January 10, 2003                                                  }
{                                                                      }
{    The Initial Developer of the Original Code is Mark Ericksen       }
{    Portions created by Mark Ericksen are                             }
{    Copyright (C) 2003 Mark Ericksen, United States of America.       }
{    All Rights Reserved.                                              }
{                                                                      }
{**********************************************************************}
{ Known Issues:
-------------------------------------------------------------------------------}
unit dws2SynEditUtils;

interface

uses Windows, SysUtils, Classes, Graphics, SynEdit, SynCompletionProposal,
  SynEditTypes, dws2Comp, dws2Symbols, dws2Exprs;

{ Core functions that are used for Code completion, Parameter display and Symbol hints. }
function PerformCodeCompletion(Editor: TCustomSynEdit; Prg: TProgram;
                             CodeProposal: TSynCompletionProposal;
                             UnitItemsList, UnitInserts: TStrings;
                             var x, y: Integer;
                             IncludeImages, IncludePropertyAccessors: Boolean): Boolean; overload;
function PerformParamProposal(Editor: TCustomSynEdit; Prg: TProgram;
                             ParamProposal: TSynCompletionProposal;
                             var x, y: Integer): Boolean; overload;
function PerformHintProposal(Editor: TCustomSynEdit; Prg: TProgram;
                             HintProposal: TSynCompletionProposal;
                             var x, y: Integer;
                             IncludeImages: Boolean): Boolean; overload;

{ Core functions that are wrapped for convenience }
function PerformCodeCompletion(Editor: TCustomSynEdit; DWScript: TDelphiWebScriptII;
                             CodeProposal: TSynCompletionProposal;
                             UnitItemsList, UnitInserts: TStrings;
                             var x, y: Integer;
                             IncludeImages, IncludePropertyAccessors: Boolean): Boolean; overload;
function PerformCodeCompletion(Editor: TCustomSynEdit; DWScript: TDelphiWebScriptII;
                             CodeProposal: TSynCompletionProposal;
                             var x, y: Integer;
                             IncludeImages, IncludePropertyAccessors: Boolean): Boolean; overload;
function PerformParamProposal(Editor: TCustomSynEdit; DWScript: TDelphiWebScriptII;
                             ParamProposal: TSynCompletionProposal;
                             var x, y: Integer): Boolean; overload;
function PerformHintProposal(Editor: TCustomSynEdit; DWScript: TDelphiWebScriptII;
                             HintProposal: TSynCompletionProposal;
                             var x, y: Integer;
                             IncludeImages: Boolean): Boolean; overload;

{ Navigation function }
procedure ToggleFromDecl2Impl(Editor: TCustomSynEdit; AProgram: TProgram);

// if a point is in a comment or a string (as defined by the highlighter)
function IsInCommentOrString(Editor: TCustomSynEdit; APoint: TPoint): Boolean;

implementation

uses dws2IDEUtils, dws2Errors, SynEditHighlighter;

{-----------------------------------------------------------------------------
  Procedure: CodeProposalProcess
  Author:    Mark Ericksen
  Date:      18-Sep-2002
  Arguments: Editor: TCustomSynEdit;
             Prg: TProgram;            (compiled DelphiWebScript program)
             CodeProposal: TSynCompletionProposal;
             UnitItemsList, UnitInserts: TStrings;  (List of symbols in units compiled into application)
             var x, y: Integer         (position of popup window)
  Result:    Boolean
  Purpose:   Return if the CodeProposal should be executed. Fill the properties
             of the component based on the current position in the editor.
-----------------------------------------------------------------------------}
function PerformCodeCompletion(Editor: TCustomSynEdit; Prg: TProgram;
  CodeProposal: TSynCompletionProposal; UnitItemsList, UnitInserts: TStrings;
  var x, y: Integer; IncludeImages, IncludePropertyAccessors: Boolean): Boolean;
var
  i, SearchStart: Integer;
  SearchSymbol: TSymbol;
  dispOpts: TdSyn_DisplayOptions;
  Context: TContext;
  ThisWordStart: TPoint;  // position where this word begins
  PrevWordStart: TPoint;  // position where previous word start
  PrevWordStop: TPoint;   // position where previous word stops
  tmpLineText: string;
begin
  Assert(Editor <> nil, 'CodeProposalExecute - The Editor parameter must be valued.');
  Assert(Prg <> nil, 'CodeProposalExecute - The Program parameter must be valued.');
  Assert(CodeProposal <> nil, 'CodeProposalExecute - The CodeProposal parameter must be valued.');

  Result := not IsInCommentOrString(Editor, Editor.CaretXY); // don't display if inside a comment or a string
  if not Result then    // if not allowed to popup,
    EXIT;               // don't continue

  { Set display options }
  dispOpts := [doSynStyle];
  if IncludeImages then                 // if graphics used,
    Include(dispOpts, doIncludeImage);  // add the graphics

  CodeProposal.ClearList;

  // get the previous symbol
  ThisWordStart := Editor.WordStart;
  PrevWordStart := Editor.PrevWordPosEx(Point(ThisWordStart.X-1, ThisWordStart.Y));   // find previous word's starting point
  PrevWordStop  := Editor.WordEndEx(PrevWordStart);

  SearchSymbol := Prg.SymbolDictionary.FindSymbolAtPosition(ThisWordStart.X, ThisWordStart.Y);
  // if no Symbol was found, search to previous symbol for context (MyClass.Somethi - Somethi won't be found, go back to class for context)
  if (SearchSymbol = nil) and (ThisWordStart.Y = PrevWordStop.Y) then  // this word and previous on same line
  begin
    tmpLineText := Editor.LineText;
    SearchStart := Length(tmpLineText);
    if ThisWordStart.X < SearchStart then
      SearchStart := ThisWordStart.X;
    // search from current word start to previous word stop (what is in between?)
    for i := SearchStart downto PrevWordStop.X do
    begin
      // if a '.' separates the words, use the previous word as a context
      if tmpLineText[i] = '.' then
      begin
        SearchSymbol := Prg.SymbolDictionary.FindSymbolAtPosition(PrevWordStart.X, PrevWordStart.Y);
        Break;
      end;
    end;
  end;

  // if a function, look at return type for base symbol
  if SearchSymbol is TFuncSymbol then
  begin
    if TFuncSymbol(SearchSymbol).Kind = fkFunction then
    begin
      if SearchSymbol is TMethodSymbol then
        SearchSymbol := TMethodSymbol(SearchSymbol).Result
      else
        SearchSymbol := TFuncSymbol(SearchSymbol).Result;
    end;
  end;

  // if Symbol found is a value symbol then get the variable type
  if SearchSymbol is TValueSymbol then
    SearchSymbol := SearchSymbol.Typ;

  // if TClassSymbol
  if (SearchSymbol is TClassSymbol) then
    LoadClassSymbolToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                             TClassSymbol(SearchSymbol), True, IncludePropertyAccessors,
                             False, dispOpts)
  // if TRecordSymbol
  else if (SearchSymbol is TRecordSymbol) then
    LoadSymbolsToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                         TRecordSymbol(SearchSymbol).Members, False, True, False, dispOpts)
  // if TUnitSymbol
  else if (SearchSymbol is TUnitSymbol) then begin
    LoadSymbolsToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                         TUnitSymbol(SearchSymbol).Table, False, True, False, dispOpts);
    if TUnitSymbol(SearchSymbol).Table is TLinkedSymbolTable then
      LoadSymbolsToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                           TLinkedSymbolTable(TUnitSymbol(SearchSymbol).Table).Parent,
                           False, True, False, dispOpts);
  end
  { If there is no symbol found, load the full global set including context based ones }
  else if (SearchSymbol = nil) then begin
    { Start by examining context, if within a procedure, list those first? }
    // Check ContextMap for symbols local to the context
    Context := Prg.ContextMap.FindContext(Editor.CaretX, Editor.CaretY);
    while Assigned(Context) do  // don't stop until no contexts to check
    begin
      // add symbols local to a context
      if Assigned(Context.LocalTable) then
        LoadSymbolsToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                             Context.LocalTable, False, False, False, dispOpts,
                             Prg, Editor.CaretX, Editor.CaretY);

      // add symbols specific to a function
      if Context.ParentSym is TFuncSymbol then
      begin
        // add function parameters to the list
        LoadSymbolsToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                             TFuncSymbol(Context.ParentSym).Params,
                             False, False, False, dispOpts);
        //  add internal variables (result, self, etc) to the list
        LoadSymbolsToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                             TFuncSymbol(Context.ParentSym).InternalParams,
                             False, False, False, dispOpts,
                             Prg, Editor.CaretX, Editor.CaretY);    

        // if a method, add the object's members to the list
        if Context.ParentSym is TMethodSymbol then
          // load this class' members to the lists
          LoadClassSymbolToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                                   TMethodSymbol(Context.ParentSym).ClassSymbol,
                                   True, False, IncludePropertyAccessors, dispOpts);
      end;

      // pop up to the next level context and continue checking
      Context := Context.Parent;
    end;

    // add script specific items (shown at top)
    LoadSymbolsToStrings(CodeProposal.ItemList, CodeProposal.InsertList,
                         Prg.Table, False, False{True}, IncludePropertyAccessors {False}, dispOpts,
                         Prg, Editor.CaretX, Editor.CaretY);  // limit to symbols declared before position

    { Add unit global items (shown after script-based items) }

    { if not provided pre-built lists, then fill lists here.}
    if (UnitItemsList = nil) or (UnitInserts = nil) then begin
      LoadUnitDeclaredSymbols(Prg, CodeProposal.ItemList, CodeProposal.InsertList, dispOpts, [], False);
    end
    { Provided pre-built lists of unit declared symbols, Append them now. }
    else begin
      CodeProposal.ItemList.AddStrings(UnitItemsList);
      CodeProposal.InsertList.AddStrings(UnitInserts);
    end;
  end;
end;

{-----------------------------------------------------------------------------
  Procedure: PerformParamProposal
  Author:    Mark Ericksen
  Date:      21-Sep-2002
  Arguments: Editor: TCustomSynEdit; Prg: TProgram; ParamProposal: TSynCompletionProposal; var x, y: Integer
  Result:    Boolean
  Purpose:   Will show the Param Proposal dialog filled with the data for the appropriate symbol.
-----------------------------------------------------------------------------}
function PerformParamProposal(Editor: TCustomSynEdit; Prg: TProgram;
                             ParamProposal: TSynCompletionProposal;
                             var x, y: Integer): Boolean;
var
  locLine: String;
  TmpX, TmpY, StartX, StartY,
  TmpLocation: Integer;
  FoundSymbol: TSymbol;
  p: Integer;
  ParamText: string;
  tmpPoint: TPoint;
  ParamDelim: string;

  { Related to paren matching (taken from SynEdit.pas GetMatchingBracketEx() }
  Test: Char;
  NumBrackets: Integer;
  isCommentOrString: Boolean;
  thisParam: string;
begin
  Assert(Assigned(Editor.Highlighter), 'A highligher must be assigned to the editor.');

  with Editor do
  begin
    { We start by decrementing X, by adding a ' ' to then end of the line it makes it so
      we don't lose any meaningful data when a line reads like this "thing," because
      the last character is a ',' (it would have been skipped by first dec(X). }
    locLine := LineText + ' ';

    //go back from the cursor and find the first open paren
    TmpX := CaretX;
    TmpY := CaretY;
    if TmpX > Length(locLine) then
      TmpX := Length(locLine)
    else if TmpX = 1 then
      TmpX := 2;     // immediately gets decremented (allows it to work when at beginning of line)

    NumBrackets := 0;
    FoundSymbol := nil;
    TmpLocation := 0;
    dec(TmpX);
    while (TmpX > 0) and (TmpY > 0) and (FoundSymbol = nil) do
    begin

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -