В заключительной статье разберемся с написанием скриптов для Intellisense.

Объект FoxCode

В то время, как таблица FoxCode обслуживает метаданные, которые лежат в сердце системы IntelliSense, объект FoxCode представляет собой то, что позволяет нам, как разработчикам, реально настраивать поведение IntelliSense. Объект FoxCode представляет собой экземпляр класса foxcodescript, который определен в программе foxcode.prg на основе базового класса session, и который не только определяет поведение различных операций IntelliSense но и предоставляет хуки, которые позволяют нам расширять при необходимости его функциональные возможности. Ключевые методы класса перечислены ниже в таблице:

МетодНазначение
Main Метод шаблона, вызываемый из метода Start – позволяет вставлять настраиваемый код пользователя.
Start Основной метод установки (set-up) для объекта. Должен быть явно вызван в скриптах.
DefaultScript Обработчик для символа "пробел" – триггер, используемый по умолчанию для IntelliSense
HandleMRU Обработчик для списков - Most Recently Used - наиболее поздно используемых элементов.
HandleCOps Обработчик для расширений в стиле C-операторов.
HandleCustomScripts Обработчки для пользовательских настраиваемых скриптов.
AdjustCase Для установки регистра ключевого слова в соответствии с установкой поля CASE, или по умолчанию, если установка не определена.
ReplaceWord Замещает последнее напечатанное "слово" указанным "словом".

В дополнение к перечисленным методам, объект FoxCode выставляет перечисленный ниже в таблице набор свойств. Разумеется, каждое поле в таблице FoxCode имеет соответствующее свойство в объекта FoxCode. Причиной тому, конечно, является то, что полное содержание строки таблицы FoxCode может быть послано любому исполняемому скрипту. Однако, кроме этих свойств, имеется еще ряд свойств, которые управляют другими аспектами реализации IntelliSense.

МетодНазначение
AbbrevСодержимое одноименного поля в таблице FoxCode.
CaseСодержимое одноименного поля в таблице FoxCode.
CmdСодержимое одноименного поля в таблице FoxCode.
Cursorlocchar Символ, используемый для указания места курсора по завершению исполнения скрипта (По умолчанию используется тильда -"~")
DataСодержимое одноименного поля в таблице FoxCode.
Defaultcase Регистр, который будет использоваться, если для этой записи он не определен (он будет взят из записи типа "V" в таблице FoxCode)
ExpandedСодержимое одноименного поля в таблице FoxCode.
Filename Полностью квалифицированное имя пути и имени файла для текущего открытого файла.
Fullline Полное содержание текущей линии (включая пробелы, символы табуляции и прочее)
Icon Иконка для использования в массиве элементов
Items Массива, используемый при генерации списков. Двухколоночный, но требуется в общем-то колонка 1.
  1. Items[1,1] – текст для отображения в списке
  2. Items[1,2] – подскзка значения для элемента
По умолчанию элементы списка хранятся в колонке 1. Для запрещения сортировки списка, очистите флажок ItemSort.
Itemscript Имя скрипта, который должен быть запущен после выбора элемента из списка (Необязательное)
Itemsort Определяет будут ли отсортированы элементы массива (По умолчанию = .T. )
Location Текущее окно редактирования – позволяет управлять скриптом там, где это приемлимо:
  • 0 - Командное окно (Command Window)
  • 1 - Программа
  • 8 - Код меню
  • 10 - Код в окне редактирования событий и методов
  • 12 - Окно редактирования хранимых процедур
Menuitem Элемент, который был выбран из списка (пустой, до завершения исполнения скрипта)
Paramnum В справке определено как: "Число параметров функции для вызова скрипта, сделанного внутри функции". Что называется - понимай, как хочешь.
SaveСодержимое одноименного поля в таблице FoxCode.
SourceСодержимое одноименного поля в таблице FoxCode.
TimestampСодержимое одноименного поля в таблице FoxCode.
TipСодержимое одноименного поля в таблице FoxCode.
TypeСодержимое одноименного поля в таблице FoxCode.
UniqueidСодержимое одноименного поля в таблице FoxCode.
UserСодержимое одноименного поля в таблице FoxCode.
Usertyped Текст, который напечатал пользователь (исключая ведущие пробелы, символы табуляции и символьные последовательности триггеров)
Valuetip Совет типа Quick Info, который будет отображен при FoxCode.ValueType = "T"
Valuetype Определяет, как должно толковаться возвращаемое скриптом значение
  • V (Value): Действие зависит от скрипта – может быть испольщовано для замещения напечатанного текста или, наоборот, для добавления к нему.
  • L (List): Отображает содержание массива FoxCode.Items в виде списка.
  • T (Tip): Отображает содержание свойства FoxCode.ValueTip в виде совета Quick Info

Создание скриптов

Верояно, наиболее захватывающей вещью привнесенной IntelliSense в Visual FoxPro, является воможность создавать пользовательские скрипты, которые позволяют нам значительно увеличить нашу продуктивность при разработках. Скрипт состоит из двух раздельных компонентов:

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

Вставка блока текста

Для вставки блока текста нам необходимо создать скрипт, который вернет форматированную строку для замещения сокращения, который и вызывет срабатывание скрипта. В чистом виде это не является скриптом общего назначения, поэтому мы может создать его непосредственно в поле Data записи таблицы foxcode.dbf, в которой определим сокращение, ну скажем типа приведенного ниже:

Type Abbrev Expanded Cmd Tip Data Case Save
Uhdr {}memoMemoMT

Реальный скрипт, размещенный поле Data выглядит примерно так, как приведено в блоке кода ниже. Как вы можете видеть, преамбула начинается с получения ссылки на объект FoxCode и проверяет месторасположение с целью удостовериться в том, что мы не находимся в командном окне (ну к чему там заголовок программы?).
Преамбула завершается установкой свойства ValueType объекта в FoxCode "V", что указывает на то, что объект вернет значение, которое заместит сокращение:

Скопировать код
LPARAMETER toFCObject
LOCAL lcOwner, lcName, lcVersion, lcPos, lcDesc, lcRets
lcDevName = [Andy Kramek]
lcOwner = "Tightline Computers, Inc"
IF toFCObject.Location = 0
  *** Если в командном окне - возвращаем то, что напечатали
   RETURN toFCObject.UserTyped
ELSE
  *** Для этого скрипта нам нужна установка textmerge в ON
  lcMerge = SET('TextMerge')
  SET TEXTMERGE ON
ENDIF
*** Этот скрипт вернет строку, которую мы желаем использовать для
*** замещения текста, который вызовет срабатывание IntelliSense. 
*** Устанавливаем valuetype соответствующим образов:
toFCObject.ValueType = "V"

Реальная работа скрипта производится далее. Блок кода, приведенный ниже представляет собой стандартный программный код Visual FoxPro, который определяет некоторые переменные и выстраивает форматированную строку возврата. Имеется несколько путей сделать подобное, но мы воспользуемся новой функциональностью TEXTMERGE, предлагающей некоторые великолепные возможности в этой области.

Скопировать код
LOCAL lcTxt, lcName, lcComment, lnPos
STORE "" TO lcTxt, lcName, lcComment
#DEFINE CRLF CHR(13)+CHR(10)
lcName = ALLTRIM( WONTOP() )
lcVersion = VERSION(1)
lnPos = AT( "[", lcVersion ) - 1
lcVersion = LEFT( lcVersion, lnPos )
lcDesc = ALLTRIM( INPUTBOX( 'Describe this Program or Procedure', lcOwner ))
lcRets = ALLTRIM( INPUTBOX( 'What does it return?', lcOwner, 'Logical' ))
*** Разыскиваем в строке точку вставки и устанавливаем отступ
lnspaces = AT(  toFCObject.UserTyped, toFCObject.FullLine ) -1
*** И генерируем далее реальный текст для вставки
TEXT TO lcText NOSHOW
********************************************************************
<>*** Name.....: <>
<>*** Author...: <>
<>*** Date.....: <>
<>*** Notice...: Copyright (c) <> <>
<>*** Compiler.: <>
<>*** Function.: <>
<>*** Returns..: <>
<>********************************************************************
<>~
ENDTEXT
*** Восстанавливаем оригинальную установку textmerge
IF NOT EMPTY( lcMerge )
  SET TEXTMERGE &lcMerge
ENDIF  
RETURN lcText

Отметьте, что этот скрипт использует свойтсво FullLine объекта FoxCode для обработки отступа. Это будет работать только в случае, если вы замените пробелами символы табуляции в настройках ваших окон редактирования. Если вы используете символы табуляции (CHR(9)) то будет вставлен только один пробле на каждый символ табуляции, поэтому отступ будет некорректным.

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

Генерация списков

Движок IntelliSense обслуживает генерацию "most-recently used" и "member lists" автоматически, и здесь нет ничего такого, что нам нужно сделать для этого. Списки, генерируемые для родных команд и функций реально генерируются из таблицы с именем "FoxCode2". Копия этой таблицы включена в исходные коды, но, в отличие от основной foxcode.dbf, она не предназначена для изменений разработчиками. Поэтому (пока у нас не возникнет желания полностью переписать приложение FoxCode) мы не может запросто заменить эти списки некоим образом.

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

Определение содержания списка

Списке IntelliSense создаются заполнением массива свойства "Items" объекта FoxCode. Этот массив должен быть двухколоночным, первая из которых используется для хранения текста для элементов списка, а вторая для хранения текста Tip, связанного с этим эелементом. В дополнение к указанию содержания списка, скрипт должен сообщить движку IntelliSense, что требуется список. Мы уже видели, что свойство ValueType объекта FoxCode используется для коммуникаций - для сообщения о том, как запущенный скрипт должен толковаться, а для генерации списка - все что нам нужно, так это установить это свойство в "L".

Простейшим способом генерации списка является создание в таблице foxcode.dbf записи с типом "U", в котором в поле data определен скрипт, который явно и непосредственно заполняет требуемые свойства объекта FoxCode, так как это показано ниже:

TypeAbbrevExpandedCmdDataSave
U olist lcChoice {}
Скопировать код
LPARAMETER toFoxCode
WITH toFoxCode
    .ValueType = "L"
    DIMENSION .items[3,2]
    .items[1,1] = "'First Option'"
    .items[1,2] = "Tip for option 1"
    .items[2,1] = "'Second Option'"
    .items[2,2] = "Tip for option 2"
    .items[3,1] = "'Third Option'"
    .items[3,2] = "Tip for option 3"
    RETURN ALLTRIM( .Expanded ) ENDWITH
T

Печать "olist" с последующим вводом пробела в окне редактирования выведет список, содержащий три опции, определенные в скрипте. Возвратом содержания свойства Expanded объекта FoxCode, мы можем заместить ключевое слово значимым текстом и добавить что-либо выбранное из списка. Хотя это действительно неплохо с одной стороны, то с другой такой метод не очень гибок, поскольку в этом случае мы имеет жестко прописанный список опций непосредственно в коде скрипта. Мы конечно можем создать таблицу для хранения списков, которые мы хотим генерировать и создать отдельную запись для каждого сокращения.

И конечно, нам не хочется иметь повторение кода, который будет искаться в каждой записи. Вот в этом случае на передний план выходит запись типа "Script". Как мы уже видели ранее, мы может вызывать скрипт из поля CMD записи таблицы foxcode.dbf, просто включив имя скрипта в фигурные скобки - {scriptname}. Поэтому мы можем создать скрипт общего назначения для обслуживания поиска, генерации списка и исполнения подходящих действий, когда выбран элемент списка.

Как определить действие, когда в списке сделан выбор

Проблема в определении действия, которое нужно выполнить, когда из списка выбран элемент, заключается в том, что код, который реально создает список нам не виден. Поэтому, в то время как мы можем указать содержание списка, мы не можем непосредственно управлять последующим действием. Движок IntelliSense полагается на два свойства объекта FoxCode. Свойство Itemscript используется для указания "обслуживающего" скрипта, который будет запущен после того, как список будет закрыт, а свойство MenuItem используется для хранения текста выбранного элемента списка. Если список закроется без какого-либо выбора, это свойство, разумеется, будет пустым. Поэтому для того, чтобы указать - как IntelliSense должен отвечать на выбор элемента из списка, нам нужно создать свой собственный скрипт обработчика.

Мы уже видели ранее, что скрипты общего назначения требуют для себя в таблице Foxcode.dbf своей собственной записи типа "S", а вследствие того, что они вызываться из другой записи, то они должны быть соответствующим образом сконструированы. Секрет таких скриптов лежит в классе FoxCodeScript, который определен в IntelliSense Manager (Диспетчере IntelliSense).

Замечание:

Исходный код этого класса найдете в программе FoxCode.prg в каталоге исходников FoxCode -
C:\Program Files\Microsoft Visual FoxPro 9\Tools\xsource\VFPSource\foxcode

Для создания скрипта общего назначения, определите субкласс класса FoxCodeScript для предоставления требуемой вам функциональности и создайте его экземлпяр. Весь необходимый код, как обычно, хранится в поле Data записи таблицы Foxcode.dbf. Простейщим способом объяснения является показ, как это работает - а это действительнон намного проще, чем это прозвучало.

Как создать список управляемый таблицей

Целью является создание скрипта общего назначения, который будет:

Для первого пункта требуется таблица. Для работы с этим примером мы будем использовать таблицу ListOptions.dbf, которая имеет всего два поля и содержание, что показано ниже:

CkeyCoption
ol1 'Number One'
ol1 'Number Two'
ol1 'Number Three'
ol2 'Apples'
ol2 'Bananas'
ol2 'Cherries'

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

Как вы могли увидеть по содержанию таблицы, она распознает два ключевых слова "ol1" и "ol2". Прежде всего, нам нужно добавить в таблицу foxcode.dbf по записи для каджого из этих двух ключевых слов. Эти записи могут определять расширяемый текст для замещения ключевого слова и вызывать скрипт обработчика. В этом примере такой скрипт носит название "lkups", то есть в целом в таблицу foxcode.dbf будут добавлены три записи:

TypeAbbrevExpandedCmdDataSave
U ol1 lcChoice= {lkups}   T
U ol2 lcFruit= {lkups}   T
S lkups     <Scipt code here>  

Содержание скрипта "lkups" подробно описано ниже. Первая часть скрипта получает ссылку на объект FoxCode, создает пользовательский объект "ScriptHandler" (который представляет собой пользовательский класс на основе класса foxcodescript, определенный непосредственно в скрипте) и посылает ссылку на объект FoxCode методу обработчика Start(). (_CodeSense является новой системной переменной VFP, которая хранит имя приложения, предоставляющее функциональность IntelliSense functionality; по умолчанию она ссылается на FoxCode.app).

Эта часть кода полностью стандартная и вы можете повторять ее (с минимальными изменениями, которые связаны лишь с именами) в нескольких записях скриптов. Метод Start() в базовом классе FoxCodeScript, заполняет ряд свойств, которые требуются объекту FoxCodeScript и затем вызывает метод шаблона "Main()". Это как раз то место, где вы поместите свой собственный код.

Скопировать код
LPARAMETER toFoxcode
IF FILE( _CODESENSE)
  *** Диспетчер IntelliSense manager найден
  *** Декларируем требуемые локальные переменные
  LOCAL luRetVal, loHandler
  SET PROCEDURE TO (_CODESENSE ) ADDITIVE
  *** Создаем экземпляр нашего класса
  loHandler = CreateObject( "ScriptHandler" )
  *** Вызываем Start() и посылаем ссылку на объект foxcode
  luRetVal  = loHandler.Start( toFoxCode )
  *** Наводим порядок и возвращаем результат
  loHandler = NULL
  IF ATC( _CODESENSE, SET( "PROC" ) )# 0
    RELEASE PROCEDURE ( _CODESENSE )
  ENDIF
  RETURN luRetVal
ELSE
  *** Do nothing at all
ENDIF

Однако, наиболее важной вещью, которую нужно запомнить является то, что скрипт в действительности будет вызыван дважды!

Первый раз он будет вызван, когда будет напечатано ключевое слово, поскольку запись в таблице foxcode.dbf специально его вызывает. В этом проходе свойство MenuItem объекта FoxCode будет пустым, так как мы еще не отобразили список, и следовательно из него ничего не выбрано. Поэтому мы должны сказать IntelliSense, что мы желаем отобразить список. Для того чтобы сделать это, мы устанавливаем свойтсов foxcode.valuetype в "L".

Далее мы вызовем пользовательский метод GetList() для заполнения массива свойства Items объекта FoxCode. Затем мы указываем через foxcode.ItemScript опять же на тот же самый скрипт, поэтому он будет вновь вызван, когда в списке будет сделан выбор. И наконец, в этом проходе, мы попросим движок IntelliSense заместить ключевое слово содержанием поля Expanded.

Скопировать код
DEFINE CLASS ScriptHandler as FoxCodeScript
  PROCEDURE Main()
    WITH This.oFoxCode
      IF EMPTY( .MenuItem )
        *** Это как раз первый раз, когда мы вызываем скрипт, 
        *** печатая сокращение. Здесь мы говорим движку
        *** IntelliSense Engine что желаем иметь список
        .ValueType = "L"
        *** Теперь посылаем ключ методу построителя списка (List Builder) 
        *** Это вернет T, когда будут найдены один или более элементов
        IF This.GetList( .UserTyped )
          *** У нас есть список, поэтому установим свойство ItemScript
          *** для повторного вызова скрипта, когда в списке будет сделан выбор
          .ItemScript = 'lkups'
          *** и замещаем ключ расширяемым текстом
          RETURN ALLTRIM( .Expanded )
        ELSE
          *** Не нашли элементов списка, поэтому возвращаем то, что напечатал пользователь
          RETURN .UserTyped
        ENDIF

Вы можете, если желаете, использовать поле Case для определения форматирования возвращаемого значения вместо прямого возврата содержания поля Expanded "как есть". Для того, чтобы сделать это - вызовите метод FoxCodeScript.AdjustCase() в предложении RETURN, при этом не потребуются параметры. Этот метод применяет подходящую команду форматирования к содержимому поля Expanded до его возврата.

Метод GetList() действительно очень прост. Он вызывается со свойством FoxCode.UserTyped, используемым в качестве параметра. (Обязательное требование - мы должны определить сокращение, которое вызывет срабатывание скрипта точно также, как оно определено в поисковой таблице). Затем метод исполняет предложение выборки в локальный массив, используя это значение в качестве фильтра. Если найдены любые значения, массив foxcode.items соответствующим образом оразмеривается и значения полей поисковой таблицы копируются в его элементы. Метод возвращает логическое значение, указывающее - были ли найдены хоть какие-то элементы.

Скопировать код
  PROCEDURE GetList( tcKey )
    LOCAL llRetVal
    LOCAL ARRAY laTemp[1]
    *** Берем любые записи соответствия из записей опций
    SELECT cOption, .F. FROM myopts ;
     WHERE cKey = tcKey ;
      INTO ARRAY laTemp
    *** Устанавливаем возвращаемое значение и закрываем таблицу
    STORE (_TALLY > 0) TO llRetVal
    USE IN myopts
    IF llRetVal
      *** заполняем массив foxcode ITEMS 
      DIMENSION This.oFoxCode.Items[ _TALLY, 2 ]
      ACOPY( laTemp, This.oFoxCode.Items )
    ENDIF
    RETURN llRetVal    
  ENDPROC

Когда элемент выбран из списка, скрипт вызывается еще один раз, но в этот раз свойство MenuItem объекта FoxCode будет содержать то, что выбрано в списке, что означает, что во втором проходе будет исполнено условие "ELSE" метода Main(). Это установить значение свойства foxcode.valuetype в "V" и возвратит то, что содержится в свойстве foxcode.MenuItem.

Скопировать код
ELSE
   *** мы сделали выбор, поэтому нам надо просто вернуть выбранный элемент
   .ValueType = "V"
   RETURN ALLTRIM( .MenuItem )
  ENDIF
ENDWITH

Установкой значения ValueType в "V" мы, кроме того, говорим движку IntelliSense, что надо вставить возвращаемое значение в текущую точку вставки, так, чтобы оно появилось после текста расширения. Отметьте, что хотя в этом случае, мы реально не изменяем возвращаемое значение, эта методология позволяет нам перехватить результат после того, как будет сделан выбор элемента, но до его вставки в код. Хотя это и затрагивает сути дела, но такая дополнительная гибкость может быть очень полезной.

Реализация скрипта общего назначения, подобного этому, позволяет нам создавать столько сокращений для списков, сколько мы пожелаем, просто добавляя соответствующие элемента в таблицу listoptions.dbf и новые записи в таблицу foxcode.dbf для идентификации ключа и вызова скрипта общего назначения.

Получение списка файлов

Нашей первой мыслью, когда этот субъект появился была – но ведь мы же уже имеем автоматизированный список "Most Recently Used files". Он конфигурируем (на закладке "General" диалогового окна Options (Параметры) в виде счетчика для установки числа файлов, хранимых в списках MRU) и поэтому он может отображать столько опций, сколько нам хочется. Однако, мы позже нашли, что для того, чтобы взять файл в список MRU, мы должны (и обязательно) хотя бы раз использовать его! Более того, до тех пор, пока мы не сделали список MRU очень большим, он в действительности полезен только для файлов, которые мы использовали самыми последними. Это потому, что число элементов в списке фиксировано, поэтому сразу после того, как это число будет достигнуто, каждый новый файл, который мы будем открывать, будет удалять из списка уже существующие. И действительно, нам ничего не остается, как получать список всех файлов вызывая диалог GetFile().

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

TypeAbbrevExpandedCmdCaseSave
U mop modify command {shofile} U T
U dop do {shofile} U T
U mof modify form {shofile} U T
U dof do form {shofile} U T
U mor modify report {shofile} U T
U dor report form {shofile} U T

Как вы можете видеть, эти сокращения расширяются до соответствующих команд либо для запуска, либо для редактирования программ, форм или отчетов. Вы можете добавить и другие веши (например, классы, этикетки, меню, документы XML и текстовые файлы) если это вам нужно. Все они вызывают скрипт общего назначения ShoFile, который выглядит следующим образом:

Скопировать код
LPARAMETER oFoxcode
IF FILE(_CODESENSE)
  LOCAL eRetVal, loFoxCodeLoader
  SET PROCEDURE TO (_CODESENSE) ADDITIVE
  loFoxCodeLoader = CreateObject("FoxCodeLoader")
  eRetVal = loFoxCodeLoader.Start(m.oFoxCode)
  loFoxCodeLoader = NULL
  IF ATC(_CODESENSE,SET("PROC"))#0
    RELEASE PROCEDURE (_CODESENSE)
  ENDIF
  RETURN m.eRetVal
ENDIF

Этот блок кода представляет собой стандартный FoxCodeScriptLoader, который вы найдете использованным во всех скриптах, использующих этот класс. The second part of the script defines the custom subclass and adds the Main() method (which is called from Start()).

Скопировать код
DEFINE CLASS FoxCodeLoader as FoxCodeScript
  PROCEDURE Main()
    LOCAL lcMenu, lcKey
    lcMenu = THIS.oFoxcode.MenuItem
    IF EMPTY( lcMenu )
      *** Ничего не выбрано, поэтому отображаем список
      lcKey  = UPPER( THIS.oFoxcode.UserTyped )
      *** Какой вид файлов мы хотим иметь в списке
      DO CASE
        CASE INLIST( lcKey, "MOP","DOP" )
          lcFiles = '*.prg'
        CASE INLIST( lcKey, "MOF", "DOF" )
          lcFiles = '*.scx'
        CASE INLIST( lcKey, "MOR", "DOR" )
          lcFiles = '*.frx'
        OTHERWISE
          lcFiles = ""
      ENDCASE
      *** заполняем массив Items для отображения
      This.GetItemList( lcFiles )
      *** Возвращаем элемент Expanded
      RETURN This.AdjustCase()
    ELSE
      *** Возвращаем выбранный элемент
      This.oFoxCode.ValueType = "V"
      RETURN lcMenu
    ENDIF
  ENDPROC
ENDDEFINE

Метод Main() просто определяет тип файла, используя ключевое слово, которое было напечатано и вызывает пользовательский метод GetItemList(). Это стандартный код FoxPro, который использует функцию ADIR() для извлечения списка каталогов и затем извлекает список файлов, которые соответствуют указанному типу из текущего корневого каталога и для каждого найденого субкаталога первого уровня. (Конечно же, код может быть легко изменен, для обслуживания дополнительных уровней каталогов). Единственный связанный с IntelliSense код находится в конце метода, где содержимое массива списка файлов копируется в коллекцию Items объекта FoxCode и свойства ValueType и ItemScript установлены для генерации списка, а определение этого указывается в качестве обработчика выбора.

Скопировать код
*** если мы что-то получили, то отобразим список
IF lnFiles > 0
  THIS.oFoxcode.ValueType = "L"
  THIS.oFoxcode.ItemScript = "ShoFile"
  *** копируем элементы во временный массив
  DIMENSION THIS.oFoxcode.Items[lnFiles ,2]
  ACOPY(laFiles,THIS.oFoxcode.Items)
ENDIF

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

Мне нравится смотреть любые скрипты, которые разрабатывают люди и ниже я привожу ссылку на FoxPro Wiki, где помещены скрипты для Intellisense: http://fox.wikis.com/wc.dll?Wiki~IntelliSenseCustomScripts~VFP

Этот перевод выполнен JS с любезного разрешения Энди Крамека.

Оригинал статьи опубликован в субботу, 17-го апреля 2005 в 3:45 пополудня в блоге автора на weblogs.foxite.com - http://weblogs.foxite.com/andykramek/archive/2005/04/17/377.aspx .

Смотри также