美文网首页
IDE调试功能开发总结

IDE调试功能开发总结

作者: 环宇飞杨 | 来源:发表于2020-02-22 18:40 被阅读0次

    效果图展示

    调试页面

    需求分析

    • 一个远程调试业务的客户端部分,代码编辑器支持实时高亮功能,语言需要支持JavaScript+Python以及meta语言。
    • 子需求1:代码行数对应显示。
    • 子需求2:断点功能 。(包括增加,删除,禁用,启用)
    • 子需求3:选中单行功能。(点击选中某行,或者断点自动停在某行,页面自动滑动到对应位置)。
    • 子需求4:快捷输入功能。(换行自动补充大括号,快捷符号输入等)
    • 子需求5:远程调试流程。

    功能调研

    可能开始查找方式不太对,没找到什么好的解决方案,去App store上找了一圈,数量极少,且多以收费内容居多,想着应该是极小众的需求,只能自己去看编译前端知识,好在高亮功能只涉及词法分析,于是拜读《编译原理》,看token解析过程、有限状态机的工作原理。但始终对于规则制定方面很是担心,一是对正则语法不太熟悉,担心漏判,导致高亮功能不能全部覆盖所有场景,二是开发周期长,补充知识是个很漫长的过程,高亮需求本属于用户体验提升的部分,为实现这么个功能放一两个月的开发时间也是够呛。

    高亮功能

    方案1

    1. 正则匹配文本,得到 注释、字符串、数字、运算符、关键字等 (每种语言写一套)
    2. 依次匹配对应色值。
    3. 编辑时监听变化,重复执行1、2步骤。

    这样最简单,但主要的缺点是不支持词和词 之间的关系 比如:

    Class Student : NSObject
    

    以上Student按理也应该变色的,但是匹配不到

    方案2

    Google搜到了js开源框架 Highlight.js ,支持一百多种语言,一百多种主题,市场上流行的IDE色调基本都支持,且有iOS移植框架可以直接使用,项目地址
    ,但悲催的是需要支持的 meta语言 是公司自己开发的,想要完美适配必须要改js源代码了,源代码500+k,并非小项目,想必改动的工作量也不少。

    移植框架的工作原理为:

    1. 其中Highlight类,使用JavaScriptCore框架解析Highlight.js 执行js脚本将代码文本转换为html。
    2. 内部类Theme 解析主题对应的css文件,给NSAttributedString设置颜色字体内容
    3. 内部类CodeAttributeString 遍历span标签,将html转换为NSAttributedString,CodeAttributeString继承自NSTextStorage,通过重写processEditing方法实现实时编辑后的高亮显示。(非全局监听,只监听编辑所在行,很高效)
    4. 将CodeAttributeString设置为UITextview的textContainer属性。
        self.textStorage = [[CodeAttributedString alloc] init];
        
        NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
        [self.textStorage addLayoutManager:layoutManager];
    
        NSTextContainer *textContainer = [[NSTextContainer alloc] init];
        [layoutManager addTextContainer:textContainer];
    
        self.textView = [[CodeTextView alloc] initWithFrame:self.view.bounds textContainer:textContainer];
    
    1. 调用setText:实现高亮显示。

    断点功能

    1.代码行数显示

    Highlight框架居然不带行数显示,所以断点没出打,没办法必须加功能。这里有个误区就是代码行数和文字行数并不是一对一的关系,屏幕宽度不一样,代码伸展的size也不一样,所以会有一行代码对应多行文本的情况。

    方案1

    新建左侧NumberLineView继承自ScrollView,将屏幕空间划分为两部分,右侧textView给左侧提供行数内容,左侧跟随右侧滑动显示。

    此方案太low,代码量和逻辑估计也不少,跳过。

    方案2

    1. 使用单一UITextview实现,先设置contentInset属性将文字部分右移。
    2. 遍历文字range 得到行数及对应rect信息。
    //这块被坑了很久,不知道有系统api已经实现,还打算逐个遍历字符根据屏幕宽度计算rect....
        [self.text enumerateSubstringsInRange:NSMakeRange(0, self.text.length) options:NSStringEnumerationByParagraphs usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
            NSRange range = [self.layoutManager glyphRangeForCharacterRange:substringRange actualCharacterRange:nil];
            CGRect rect = [self.layoutManager boundingRectForGlyphRange:range inTextContainer:self.textContainer];
            //此处 rect 就是每一行文字对应的矩形,随屏幕宽度变化而变化
        }];
    
    获取rect效果图
    行数类结构
    1. 重写drawRect方法,将行数文字和rect绘制到左侧空余部分。
    - (void)drawRect:(CGRect)rect
    {
    ...
        for (LineNumberModel *model in self.lineModelArray){
              [model.lineStr drawInRect:model.rectValve.CGRectValue];
        }
    ...
    }
    

    2.断点控制

    • 增加
      增加涉及到断点保存的场景,为提升效率本地和服务端都维护一份断点数组,断点模型需要的信息有:
    1. id //不解释
    2. 脚本id //收到远程断点的时候,需要展示对应脚本信息
    3. 行数 //用于和左侧行数栏匹配显示断点
    4. 状态 //用于显示断点启用状态
    • 删除
      调用接口,重绘UI
    • 禁用
      调用接口,重绘UI
    • 启用
      调用接口,重绘UI

    选中单行功能

    1. 自动选中
      监听到远程中断事件后,正常情况下需要做一系列的定位操作,包括打开页面、展示数据、获取对应脚本、定位到所在行等。
      另外还需要考虑异常场景,所以开始写逻辑前,最好先多想一些测试用例,比如通过断点定位不到脚本的情况,脚本和行数对应不上的情况,或者定位过程中,用户正在操作UI时的情况。
      最怕写的过程中,因为突然想起少考虑了一个重要场景,出现各种花式适配.....这种情况多了,就成了加班的噩梦。所以还不如开始就耐着性子画些脑图,流程图把自己脑子先收拾清楚再说。
    2. 点击选中
      这个比较简单了,textView增加点击手势,遍历数组判断点击区域是否属于行数内某rect范围内,是的话就标记到drawRect里绘制。


      点击选中42行

    有个冲突的地方是增加tap手势以后,textView就不能响应弹出键盘了,所以还需要在非代码行数的范围内主动弹出键盘,并将光标定位在点击位置,也是现有API。

    if (isNotNumberViewRect){
        self.editable = YES;
        [self becomeFirstResponder];
        CGPoint point = [tap locationInView:tap.view];
        UITextRange *range = [self characterRangeAtPoint:point];
        self.selectedTextRange = range; 
    }
    
    1. 软键盘快捷输入
      软键盘写代码主要有以下缺点:
    • 不好定位光标。发现一个单词输错几个字符,要定位到错误位置简直崩溃。
      解决方案,增加 ←,→快捷输入按钮,上下相对好操作些,就不加按钮了,空间有限。
    • 代码用到的符号都藏得很深。比如成对的 (),[],{},"",''。


      快捷输入

      -'{' 符输入后换行自动补充 '}'。
      逻辑原理:

    1. 检测\n符号
    2. 找出换行前最后一个非空白字符是不是左花括号:
    3. 插入tab并再次换行
    4. 补齐右花括号
    
    
    • 自动缩进?
    • 自动平衡花括号?
    • 代码提示? 没想到什么好的方案,貌似只能本地建立个词汇库,然后通过谓词查找,成本不低。

    远程调试

    调试流程

    1. 启动调试
    2. 启动长连接监听远程事件。(断点、异常,或日志)
    3. 断点操作。(增加,删除,启用,禁用)
    4. 收到远程事件,定位UI。
    5. 点击断点下一步、继续的执行逻辑。

    相关文章

      网友评论

          本文标题:IDE调试功能开发总结

          本文链接:https://www.haomeiwen.com/subject/sdilqhtx.html