找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3408|回复: 6

【VB】论ide部分功能的实现(语法高亮),(智能感知)

[复制链接]
发表于 2014-12-19 22:31:35 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
1f1c367adab44aed8aac5a4eb11c8701a08bfbbb.jpg
Ok  let us start!
本贴讨论ide编辑器的两个功能:一个是Highlighting(语法高亮),另一个是Intellisence(智能感知){以下简称:IS}
=====================================================================================================================
好,先看IS
以一款vbs编辑器为例,vbs功能之所以强大,是因为它可以调用com,windows提供了种类丰富,功能强大的各类com组件
com组件种类繁多,让我们眼花缭乱,一款好的编辑器应该提供com组件的属性与方法来便于我们编程
那么问题来了:如何实现?
1.我们可以把所有com组件的所有属性与方法存进类数据库文件,在编辑时进行调用
2.我们可以获取系统注册的com组件的信息,scan com组件字符串,然后筛选调用
就上述两种方法,大家可以讨论,第一种繁琐,而且不是dynamic,显然应该使用方法2
所以关键技术放在了如何与系统的com组件注册机制获得connection
好的,这里就引出typelib infomation,如图: 155094eef01f3a29074c32649b25bc315d607c9c.jpg
  1. Dim i As Integer
  2.     Dim oTLB As InterfaceInfo
  3.     Dim tar As Object
  4.     Set tar = CreateObject(objectName)
  5.     Set oTLB = tli.InterfaceInfoFromObject(tar)
  6.     listA.Clear
  7.     For i = 1 To oTLB.Members.Count
  8.         Select Case oTLB.Members(i).InvokeKind
  9.         Case INVOKE_CONST
  10.             listA.AddItem "常数:" & oTLB.Members(i).Name
  11.         Case INVOKE_EVENTFUNC
  12.             listA.AddItem "事件:" & oTLB.Members(i).Name
  13.         Case INVOKE_FUNC
  14.             listA.AddItem "方法:" & oTLB.Members(i).Name
  15.         Case INVOKE_PROPERTYGET
  16.             listA.AddItem "属性(Get):" & oTLB.Members(i).Name
  17.         Case INVOKE_PROPERTYPUT
  18.             listA.AddItem "属性(Let):" & oTLB.Members(i).Name
  19.         Case INVOKE_PROPERTYPUTREF
  20.             listA.AddItem "属性(Set):" & oTLB.Members(i).Name
  21.         Case INVOKE_UNKNOWN
  22.             listA.AddItem "未知:" & oTLB.Members(i).Name
  23.         End Select
  24.     Next
复制代码

tar即为目标com组件,先创建名为tar的com对象
然后用tli库的InterfaceInfoFromObject方法获得com对象
利用i计数器和oTLB.Members.Count控制循环,获取该com组件在系统内注册的信息
那么INVOKE_CONST即为常数INVOKE_EVENTFUNC为事件INVOKE_FUNC为方法等等。。
好了,至此我们将信息录入listbox,下面只要让listbox跟踪插入符的移动,便可以做出以我乱VS(出自于:以假乱真)的IS啦
那么具体在vb6的方法实现是,将form或者一个picture的font属性设置得和richtextbox一样,用“TextWidth(列数)”方法计算listbox的left
用TextHeight(当前行-显示的首行)计算listbox的top,那么关于获得编辑文本框的光标行列,显示之首行等信息,我已经封装成一个模块,大家可以在这里下载(源码同样包含): Module1.bas (6 KB, 下载次数: 6)
继续,关于如何搜索com组件的关键字,我是这样解决的:因为在vbs中引用com代码通常是这样的
dim a
set a = createobject("xxx.xxx")
a.
这里只要输出“.”即可弹出listbox,然后根据语法set 空格(n个)变量名(可能未声明)createobject括号 字符串xxx.xxx(注意,这个语句可能出现在变量使用之上文的任意位置)获得这个xxx.xxx
然后取得类似 变量名 点 的式子 然后方法如上搜索属性方法,具体代码参见vbspad源码。
  1. '这是我用来识别com组件连接字符串的代码:
  2. Public Function ScanObjects(valName As String, cTextBox As RichTextBox)
  3.     Dim ts As String
  4.     Set objRegEx = New RegExp
  5.     With objRegEx
  6.         .MultiLine = True
  7.         .IgnoreCase = True
  8.         .Global = True
  9.     End With
  10.     'Dim matchStr As String
  11.     Dim eXMatCol As MatchCollection, eXMat As Match
  12.    
  13.     objRegEx.Pattern = "set\s*" & valName & "\s*=\s*createobject\s*\(" & Chr(34) & ".*" & Chr(34) & "\)"
  14.     If objRegEx.Test(cTextBox.Text) Then
  15.         Set eXMatCol = objRegEx.Execute(cTextBox.Text)
  16.         Set eXMat = eXMatCol.Item(eXMatCol.Count - 1)
  17.         
  18.         ts = eXMat.Value
  19.         objRegEx.Pattern = Chr(34) & ".*" & Chr(34)
  20.         If objRegEx.Test(ts) Then
  21.             Set eXMatCol = objRegEx.Execute(cTextBox.Text)
  22.             Set eXMat = eXMatCol.Item(eXMatCol.Count - 1)
  23.             ScanObjects = Replace(eXMat.Value, Chr(34), vbNullString)
  24.             Exit Function
  25.         End If
  26.     End If
  27. End Function
复制代码

那么关于字符串的匹配与搜索呢,我是这样想的,例如,有com组件xxx.xxx,其下有方法abc整形参数一个
dim var
set var = createobject("xxx.xxx")
var.abc(1)
那么listbox里边一定会列出abc
我们即可在richtextbox的keypress事件中监测键码“上键”和“下键”,检测到将listbox setfocus,同时,listbox监测键码 空格(32)回车(13)将listbox中的内容copy到richtextbox中
最后richtextbox.setfocus,list.visible=false
  1. '这段代码用来检测变量
  2. Public Function GetVarName(cTextBox As RichTextBox)
  3.     Dim ts1 As String
  4.     Dim eXMatCol As MatchCollection, eXMat As Match
  5.     ts1 = GetLineText(cTextBox, GetCurPos(cTextBox).Y - 1)
  6.    
  7.     Set objRegEx = New RegExp
  8.     With objRegEx
  9.         .MultiLine = True
  10.         .IgnoreCase = True
  11.         .Global = True
  12.     End With
  13.    
  14.     objRegEx.Pattern = "\w*\."
  15.     If objRegEx.Test(cTextBox.Text) Then
  16.         Set eXMatCol = objRegEx.Execute(cTextBox.Text)
  17.         Set eXMat = eXMatCol.Item(eXMatCol.Count - 1)
  18.         
  19.         GetVarName = Replace(eXMat.Value, ".", vbNullString)
  20.         Exit Function
  21.     End If
  22. End Function
复制代码

搜索同名属性方法:
Private Sub ScanListWords()
Dim i As Integer
For i = 0 To List1.ListCount - 1
If InStr(1, LCase(List1.List(i)), LCase(pStr)) <> 0 The
List1.ListIndex = i
End If
Next
End Sub

好了,IS告一段落下面该讲讲语法高亮了
=================================================================================================================================================================================================
语法高亮,实在是伟大的发明,它能让满眼乱七八糟的数字与符号看起来富有意义
关于vb实现语法高亮,最容易想到的便是richtextbox(简称:rtb)控件
但是呢rtb在对大量代码染色时速度很慢,不过我还是决定试一试
说到rtb的染色,rtb上色有两种办法(不说子类化重绘,我没有尝试过子类化重绘):
1.配合使用selstart,sellenth,selcolor属性(我给他起个名字叫:三属性渲染)。2.使用rtb格式化文档(我尝试失败)
那么咱们讲讲三属性渲染:
对于rtb控件的染色提速有以下几点方法:
1.加载时全部染色(很耗时),然后对于正在编辑的行,进行单独染色(初始全染,编辑分染)
2.对于显示的多行进行染色,当显示首行有变动,用timer监测变动及时补染。对于正在编辑的行,再单独染色(分时分段渲染,编辑分染)
由于vbspad也属于早起开发的工具,在当时,我采用了“初始全染,编辑分染”的方法,虽然方法2效率更高。
那么对于关键字的识别,主要还是用到了正则表达式。
关于正则,笔者不赘述,大家可以参考这篇文档(版权归原作者所有,仅供学习交流,本人不负任何责任): vb6_正则表达式.pdf (326.55 KB, 下载次数: 10)
那么在我的源码中,正则匹配部分位于Module2中:
  1. Option Explicit

  2. Dim objRegEx As RegExp
  3. Dim aRWord() As String
  4. Dim aFWord() As String
  5. Dim aOWord() As String

  6. Public Sub InitHighLig()
  7.     aRWord = Split("Call|Case|Class|Const|Debug|Dim|Do|Each|Else|ElseIf|Empty|End|End If|End With|End Sub|End Function|Eqv|Exit Function|Exit Sub|Exit For|Exit Do|Exit While|Error|Err|False|For|Function|Get|Goto|If|Imp|In|Is|Let|Loop|New|Next|Nothing|Null|On|Option|Preserve|Private|Public|ReDim|Rem|Resume|Select|Set|Sub|Then|To|True|Until|WEnd|While|With", "|")
  8.     aFWord = Split("Abs|Array|Asc|Atn|CBool|CByte|CCur|CDate|CDbl|Chr|CInt|CLng|Cos|CreateObject|CSng|CStr|Date|DateAdd|DateDiff|DatePart|DateSerial|DateValue|Day|Eval|Exp|Filter|Fix|FormatCurrency|FormatDateTime|FormatNumber|FormatPercent|GetLocale|GetObject|GetRef|Hex|Hour|InputBox|InStr|InStrRev|Int|IsArray|IsDate|IsEmpty|IsNull|IsNumeric|IsObject|Join|LBound|LCase|Left|Len|LoadPicture|Log|LTrim|Mid|Minute|Month|MonthName|MsgBox|Now|Oct|Replace|RGB|Right|Rnd|Round|RTrim|ScriptEngine|ScriptEngineBuildVersion|ScriptEngineMajorVersion|ScriptEngineMinorVersion|Second|SetLocale|Sgn|Sin|Space|Split|Sqr|StrComp|String|StrReverse|Tan|Time|Timer|TimeSerial|TimeValue|Trim|TypeName|UBound|UCase|VarType|Weekday|WeekdayName|Year", "|")
  9.     aOWord = Split(">|<|=|+|-|*|/|^|Mod|Not|And|Or|Xor", "|")
  10.     Set objRegEx = New RegExp
  11.     With objRegEx
  12.         .MultiLine = False
  13.         .IgnoreCase = True
  14.         .Global = True
  15.     End With
  16. End Sub

  17. Public Sub HigLigCurLnB(tB As RichTextBox, rTBSSt As Long, Optional ln As Long)
  18.     On Error GoTo EH_HLCL:
  19.     Dim sRWords As String, aRWords() As String
  20.     Dim rST As Long
  21.     sRWords = "dim |option explicit|if | then|else|end if|do|loop|"
  22.     aRWords = Split(sRWords, "|")
  23.     rST = tB.SelStart
  24.     Dim t As Variant
  25.     For Each t In aRWords
  26.         If InStrRev(LCase(tB.Text), t, rTBSSt) Then
  27.             tB.SelStart = tB.SelStart - Len(t)
  28.             tB.SelLength = Len(t)
  29.             tB.SelColor = &HFF0000
  30.             tB.SelLength = 0
  31.             tB.SelColor = &H0&
  32.             tB.SelStart = rST
  33.             tB.SelColor = &H0&
  34.             Exit For
  35.         End If
  36.     Next
  37. EH_HLCL:
  38.     If Err <> 0 Then
  39.         tB.SelLength = 0
  40.         tB.SelColor = &H0&
  41.     End If
  42. End Sub

  43. Public Function FormatCurCode(ln As Long)
  44. 'If a Then a = 3



  45. End Function
  46. Public Sub HigLigCurLnC(cTextBox As RichTextBox, lnSelectionStart As Long, Optional ln As Long)
  47.     Dim s1 As String
  48.     Dim st As String
  49.     Dim i As Integer
  50.     With cTextBox
  51.         If GetCurPos(cTextBox).Y = 1 Then
  52.             st = Mid(.Text, InStrRev(Mid(.Text, 1, lnSelectionStart), vbCrLf) + 1)
  53.         Else
  54.             st = Mid(.Text, InStrRev(Mid(.Text, 1, lnSelectionStart), vbCrLf) + 2)
  55.         End If
  56.         
  57.         MsgBox Chr(34) & st & """"
  58.         i = Len(st)
  59.         Do While i <= 1
  60.             's1 = Mid(st, i,
  61.             If IsRWord(s1) = True Then
  62.                 .SelStart = lnSelectionStart - i
  63.                 .SelLength = Len(s1)
  64.                 .SelColor = &HFF0000
  65.                 i = i - Len(s1)
  66.             End If
  67.         Loop
  68.         .SelLength = 0
  69.         .SelStart = lnSelectionStart
  70.         .SelColor = &H0&
  71.     End With
  72. End Sub

  73. Public Sub HigLigCurLn(cTextBox As RichTextBox, lnSelectionStart As Long, Optional colorAll As Boolean = False)
  74.     Dim st1 As String
  75.     Dim t As Variant, i As Integer
  76.     Dim fPos As Integer, rPos As Long
  77.     Dim eXMatCol As MatchCollection, eXMat As Match
  78.     rPos = lnSelectionStart
  79.    
  80.     st1 = GetLineText(cTextBox, GetCurPos(cTextBox).Y - 1)
  81.     If colorAll = True Then st1 = cTextBox.Text
  82.     If colorAll = False Then
  83.         With cTextBox
  84.             If lnSelectionStart <= (GetCurPos(cTextBox).X - 1) Then
  85.                 .SelStart = .SelStart - ((GetCurPos(cTextBox).X - 1) - lnSelectionStart)
  86.             Else
  87.                 .SelStart = .SelStart + (lnSelectionStart - (GetCurPos(cTextBox).X - 1))
  88.             End If
  89.             .SelLength = Len(st1) - 2
  90.             .SelColor = &H0&
  91.         End With
  92.     End If
  93.    
  94.     For Each t In aRWord()
  95.         objRegEx.Pattern = "\b" & t & "\b"
  96.         If objRegEx.Test(st1) Then
  97.             Set eXMatCol = objRegEx.Execute(st1)
  98.             'MsgBox eXMatCol.Count
  99.             
  100.             For i = 0 To eXMatCol.Count - 1
  101.                 Set eXMat = eXMatCol.Item(i)
  102.                 fPos = eXMat.FirstIndex
  103.                 With cTextBox
  104.                     'MsgBox "fpos:" & fPos & vbCrLf & "cpos:" & GetCurPos(cTextBox).x - 1 '====
  105.                     If fPos <= GetCurPos(cTextBox).X - 1 Then
  106.                         .SelStart = .SelStart - ((GetCurPos(cTextBox).X - 1) - fPos)
  107.                     Else
  108.                         .SelStart = .SelStart + (fPos - (GetCurPos(cTextBox).X - 1))
  109.                     End If
  110.                     .SelLength = eXMatCol(0).Length
  111.                     .SelColor = &HFF0000
  112.                     '.SelColor = vbRed
  113.                     .SelText = objRegEx.Replace(.SelText, t)
  114.                 End With
  115.             Next
  116.         End If
  117.     Next
  118.     For Each t In aFWord()
  119.         objRegEx.Pattern = "\b" & t & "\b"
  120.         If objRegEx.Test(st1) Then
  121.             Set eXMatCol = objRegEx.Execute(st1)
  122.             For i = 0 To eXMatCol.Count - 1
  123.                 Set eXMat = eXMatCol.Item(i)
  124.                 fPos = eXMat.FirstIndex
  125.                 With cTextBox
  126.                     If fPos <= GetCurPos(cTextBox).X - 1 Then
  127.                         .SelStart = .SelStart - ((GetCurPos(cTextBox).X - 1) - fPos)
  128.                     Else
  129.                         .SelStart = .SelStart + (fPos - (GetCurPos(cTextBox).X - 1))
  130.                     End If
  131.                     .SelLength = eXMatCol(0).Length
  132.                     .SelColor = &HC000C0
  133.                     .SelText = objRegEx.Replace(.SelText, t)
  134.                 End With
  135.             Next
  136.         End If
  137.     Next
  138.     For Each t In aOWord()
  139.         Select Case t
  140.         Case "Mod", "Not", "And", "Or", "Xor"
  141.             objRegEx.Pattern = "\b" & t & "\b"
  142.         Case ">", "<", "=", "^", "-", "/"
  143.             objRegEx.Pattern = t
  144.         Case "+", "*"
  145.             objRegEx.Pattern = "" & t
  146.         End Select
  147.         
  148.         If objRegEx.Test(st1) Then
  149.             Set eXMatCol = objRegEx.Execute(st1)
  150.             For i = 0 To eXMatCol.Count - 1
  151.                 Set eXMat = eXMatCol.Item(i)
  152.                 fPos = eXMat.FirstIndex
  153.                 With cTextBox
  154.                     If fPos <= GetCurPos(cTextBox).X - 1 Then
  155.                         .SelStart = .SelStart - ((GetCurPos(cTextBox).X - 1) - fPos)
  156.                     Else
  157.                         .SelStart = .SelStart + (fPos - (GetCurPos(cTextBox).X - 1))
  158.                     End If
  159.                     .SelLength = eXMatCol(0).Length
  160.                     .SelColor = &H80FF&
  161.                     If t = "Mod" Or t = "Not" Or t = "And" Or t = "Or" Or t = "Xor" Then .SelText = objRegEx.Replace(.SelText, t)
  162.                 End With
  163.             Next
  164.         End If
  165.     Next
  166.     '字符串
  167.     objRegEx.Pattern = Chr(34) & ".*" & Chr(34)
  168.     If objRegEx.Test(st1) Then
  169.         Set eXMatCol = objRegEx.Execute(st1)
  170.         For i = 0 To eXMatCol.Count - 1
  171.             Set eXMat = eXMatCol.Item(i)
  172.             fPos = eXMat.FirstIndex
  173.             With cTextBox
  174.                 If fPos <= GetCurPos(cTextBox).X - 1 Then
  175.                     .SelStart = .SelStart - ((GetCurPos(cTextBox).X - 1) - fPos)
  176.                 Else
  177.                     .SelStart = .SelStart + (fPos - (GetCurPos(cTextBox).X - 1))
  178.                 End If
  179.                 .SelLength = eXMatCol(0).Length
  180.                 .SelColor = &H808080
  181.             End With
  182.         Next
  183.     End If
  184.     '注释
  185.     objRegEx.Pattern = "'\w*"
  186.     If objRegEx.Test(st1) Then
  187.         Set eXMatCol = objRegEx.Execute(st1)
  188.         Set eXMat = eXMatCol.Item(0)
  189.         fPos = eXMat.FirstIndex
  190.         With cTextBox
  191.             If fPos <= GetCurPos(cTextBox).X - 1 Then
  192.                 .SelStart = .SelStart - ((GetCurPos(cTextBox).X - 1) - fPos)
  193.             Else
  194.                 .SelStart = .SelStart + (fPos - (GetCurPos(cTextBox).X - 1))
  195.             End If
  196.             .SelLength = eXMatCol(0).Length
  197.             .SelColor = &HC000&
  198.         End With
  199.     End If
  200.    
  201.     With cTextBox
  202.         .SelStart = rPos
  203.         .SelLength = 0
  204.         .SelColor = &H0&
  205.     End With
  206. End Sub

  207. Private Function IsRWord(wordText As String) As Boolean
  208.     Dim t As Variant
  209.     IsRWord = False
  210.     For Each t In aRWord()
  211.         If LCase(wordText) = LCase(t) Then
  212.             IsRWord = True
  213.             Exit Function
  214.         End If
  215.     Next
  216. End Function
复制代码

这是vbspad的源码,bug有很多,请大家谅解 VP2_Source.zip (111.77 KB, 下载次数: 48)
==============================================================================================================================================================================================
结语:
方法是人想出来的,路是人踩出来的,条条大路通罗马,种种方法能解题。以上是鄙人的一点拙见,仅供大家参考。
时至今日,鄙人还在编译原理和人工智能的道路上奋进。世界的发展靠的是人的联系,谨希望同大家共勉,多多交流沟通。
一个人的奋斗也离不开千千万万朋友的帮助,这里特别感谢站长@0xAA55 ,还有@tesla.angela 没有他们的支持,我很难走到今天。
回复

使用道具 举报

发表于 2014-12-19 22:42:02 来自手机 | 显示全部楼层
哈哈 你这个看着效果真是赞!
回复 赞! 靠!

使用道具 举报

发表于 2014-12-19 22:42:52 | 显示全部楼层
没有横向滚动条,没有菜单。。。还有主界面无需使用自定义吧!
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2014-12-19 23:34:54 | 显示全部楼层
@美俪女神  {:soso_e113:} 捕获.JPG
回复 赞! 靠!

使用道具 举报

发表于 2022-11-23 21:57:18 | 显示全部楼层
非常棒!
回复

使用道具 举报

发表于 2022-11-29 17:46:52 | 显示全部楼层
在win10 里面行号显示有问题,还有关键字提示不会出来
回复 赞! 靠!

使用道具 举报

发表于 2023-7-6 11:01:29 | 显示全部楼层
很好,试一下
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-21 21:38 , Processed in 0.045250 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表