3rwgk-6aaaa-aaaad-qey6a-cai.icp0.io Open in urlscan Pro
2a00:fb01:400:200:5000:eeff:fe3d:aa0d  Public Scan

URL: https://3rwgk-6aaaa-aaaad-qey6a-cai.icp0.io/write-an-indent-comments-plugin-for-xcode.html
Submission: On January 16 via api from US — Scanned from CH

Form analysis 1 forms found in the DOM

Name: searchform

<form name="searchform" class="form u-search-form">
  <i class="icon fas fa-search fa-fw"></i>
  <input type="text" class="input u-search-input" placeholder="Search...">
</form>

Text Content

Xcode代码注释自动缩进插件开发教程

 * 
 * 

 * 首页
 * 分类
   * 学习园地
     * 编程开发
     * 算法之美
     * 逆向工程
     * CTF比赛
   * 娱乐天地
     * 奇思妙想
     * 挑战智慧
     * 魔术学堂
   * 其它分类
     * 博客折腾
     * 故事小说
     * 过期代码
 * 友链
 * 留言
 * 关于


 * 
 * * 首页
   * 分类
     * 学习园地
       * 编程开发
       * 算法之美
       * 逆向工程
       * CTF比赛
     * 娱乐天地
       * 奇思妙想
       * 挑战智慧
       * 魔术学堂
     * 其它分类
       * 博客折腾
       * 故事小说
       * 过期代码
   * 友链
   * 留言
   * 关于

Volantis





XCODE代码注释自动缩进插件开发教程

才怪

学习园地编程开发

发布于:2015年12月15日

次浏览



一、插件需求

自从公司启用代码review以来,每个开发者的代码风格渐渐保持一致了,看到规范统一的代码就是觉得比较舒服。

不过Xcode的代码注释功能一直用着很别扭,比如下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


COPY

//注释前:
- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];
}

//注释后:
- (void)viewDidLoad
{
    [super viewDidLoad];

//    self.view.backgroundColor = [UIColor whiteColor];
}


可以看到,Xcode只是在行开头加上注释符,注释后的代码缩进对不齐,很难看。这对患有神经感官歇斯底里毛细血管穿梭图鲁西斯症候群(简称强迫症)的人来说,是一件非常痛苦的事情。

在stackoverflow搜了一下,发现有人也提了这个问题,然后有个人回答说:

>  1. 你先按command + [把代码往左缩进到最前面
>  2. 再按command + /注释代码
>  3. 最后按command + ]把代码往右缩进

结果这条回答被采纳为最差答案。

所以我只能自己写个插件来让注释自动缩进了,首先新建一个Xcode插件工程,比较详细的创建过程可以见《Xcode插件AllTargets开发教程》。


二、编写过程

一开始要先整理一下写插件的思路,我们使用快捷键command +
/的时候,Xcode肯定会调用一个方法来注释代码,这个方法实现的功能应该是在代码行最前面加上//注释符。
而当我们写的代码有缩进的话,缩进的地方都是空格,所以我们可以hook注释的方法,把注释符改为插入到第一个非空格字符前就行了。

接下来就开始查找代码注释的方法了,首先在Xcode的私有类头文件里搜索comment,可以发现一个比较可疑的方法:-
(void)commentAndUncommentCurrentLines:(id)arg1;,hook这个方法,把参数arg1打印出来,参考代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


COPY

#import "DVTSourceTextView+Hook.h"

@implementation DVTSourceTextView (Hook)

+ (void)hook
{
    [self jr_swizzleMethod:@selector(commentAndUncommentCurrentLines:)
                withMethod:@selector(hook_commentAndUncommentCurrentLines:)
                     error:nil];
}

- (void)hook_commentAndUncommentCurrentLines:(id)arg1
{
    NSLog(@"%@", arg1);
    [self hook_commentAndUncommentCurrentLines:arg1];
}

@end


使用command + /对代码进行注释和反注释,输出结果为:

> <NSMenuItem: 0x7f9ec494c8f0 Comment Selection>
> <NSMenuItem: 0x7f9ec494c8f0 Uncomment Selection>

由此可知,使用快捷键注释,实际上是调用了Xcode菜单栏点击的方法。而当我们注释代码时,会有log打印,也说明找对了方法。

commentAndUncommentCurrentLines:这个方法位于DVTSourceTextView类中,而这个类位于DVTKit.framework里,接下来打开反汇编软件Hopper
Disassembler,把DVTKit.framework拖进去进行反汇编。

搜索并选中commentAndUncommentCurrentLines:方法,按alt + enter生成伪代码,由于代码太长所以只贴出关键代码:

1
2
3
4
5
6
7
8


COPY

void -[DVTSourceTextView commentAndUncommentCurrentLines:](void * self, void * _cmd, void * arg2)
{
    //......

    rax = (r12)(r15, @selector(stringByTogglingCommentsInLineRange:), rdx, r13);

    //......
}


由上面的代码可知,stringByTogglingCommentsInLineRange:方法返回了注释或反注释后的字符串,接着再搜索并查看该方法的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12


COPY

void * -[DVTSourceLanguageService stringByTogglingCommentsInLineRange:](void * self, void * _cmd, struct _NSRange arg2) 
{
    //......

    if (var_70 == 0x2) {
        rbx = [[rdi stringByUncommentingString:r15] retain];
    } else {
        rbx = [[rdi stringByCommentingString:r15] retain];
    }

    //......
}


同理,继续查看stringByCommentingString:方法的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41


COPY

void * -[DVTSourceLanguageService stringByCommentingString:](void * self, void * _cmd, void * arg2)
{
    rdx = arg2;
    r15 = self;
    r12 = [rdx retain];
    r14 = *objc_msgSend;
    rbx = [[r15 lineCommentPrefixes] retain];
    r13 = [[rbx firstObject] retain];
    [rbx release];
    if ([r13 length] != 0x0) {
            r15 = r13;
    }
    else {
            r14 = *objc_msgSend;
            var_30 = r12;
            rbx = [[r15 blockCommentCircumfixes] retain];
            r12 = [[rbx firstObject] retain];
            r15 = *objc_release;
            [rbx release];
            rbx = r15;
            r15 = [[r12 firstObject] retain];
            [r13 release];
            r13 = [[r12 lastObject] retain];
            [r12 release];
            if (r13 != 0x0) {
                    r12 = [[var_30 stringByAppendingString:r13] retain];
                    (rbx)(var_30, @selector(stringByAppendingString:));
                    (rbx)(r13, @selector(stringByAppendingString:));
            }
            else {
                    r12 = var_30;
            }
    }
    rbx = [[r15 stringByAppendingString:r12] retain];
    r14 = *objc_release;
    [r12 release];
    [r15 release];
    rdi = rbx;
    rax = [rdi autorelease];
    return rax;
}


这个方法的作用是把待注释的代码加上注释符进行注释,这也是Xcode注释代码的具体实现方法,将伪代码翻译成OC代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


COPY

- (NSString *)stringByCommentingString:(NSString *)commentingString
{
    NSString *lineCommentPrefix = [self.lineCommentPrefixes firstObject];
    
    if (lineCommentPrefix.length == 0) {
        
        // 使用 `/* */` 注释块
        NSArray *blockCommentCircumfix = [self.blockCommentCircumfixes firstObject];
        lineCommentPrefix = [blockCommentCircumfix firstObject];
        
        NSString *lineCommentSuffix = [blockCommentCircumfix lastObject];
        if (lineCommentSuffix) {
            commentingString = [commentingString stringByAppendingString:lineCommentSuffix];
        }
    }

    //在待注释的代码最前面加上注释符
    return [lineCommentPrefix stringByAppendingString:commentingString];
}


因此我们可以hook这个方法,在第一个非空格字符的位置插入注释符。
如果某一行代码是空行的话,就不需要注释了,我看了大部分的编辑器都是这么处理的。
参考代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28


COPY

- (NSString *)hook_stringByCommentingString:(NSString *)commentingString
{
    NSString *lineCommentPrefix = [self.lineCommentPrefixes firstObject];
    
    if (lineCommentPrefix.length == 0) {
        
        // 使用 `/* */` 注释块
        NSArray *blockCommentCircumfix = [self.blockCommentCircumfixes firstObject];
        lineCommentPrefix = [blockCommentCircumfix firstObject];
        
        NSString *lineCommentSuffix = [blockCommentCircumfix lastObject];
        if (lineCommentSuffix) {
            commentingString = [commentingString stringByAppendingString:lineCommentSuffix];
        }
    }

    // 判断代码是否含有非空格字符
    NSRange range = [commentingString rangeOfString:@"[^\\s]" options:NSRegularExpressionSearch];
    if (range.location == NSNotFound) {
        // 如果没有非空格字符,就不注释
        return commentingString;
    }
    
    // 在第一个非空格字符的位置插入注释符
    NSMutableString *mutableString = [commentingString mutableCopy];
    [mutableString insertString:lineCommentPrefix atIndex:range.location];
    return [mutableString copy];
}



三、下载地址

安装插件后,使用效果如下所示:


插件代码下载地址为:https://github.com/poboke/IndentComments

> 博客内容遵循 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议
> 
> 本文永久链接是:https://www.poboke.com/write-an-indent-comments-plugin-for-xcode.html

更新于:2021年9月1日

iOS

Objective-C

逆向

Xcode程序员鼓励师插件Miku

一、插件介绍最近Atom编辑器又出了一个插件:atom-miku,装上这个插件后编辑器会出现一个程序员鼓励师Miku,敲代码时Miku会唱歌和跳舞,停止敲代码时Miku的动作就慢了下来,简直是宅...

Xcode装逼插件ActivatePowerMode

一、插件介绍最近微博上在流传一个Atom编辑器的插件:activate-power-mode,装上这个插件后打字会有震屏和火花效果,非常牛逼,效果如下:
据说有人用了,并且还是机械键盘,差点被同...

评论

昵称
邮箱
网址(可选)

预览:


0  字
提交

评论

刷新
Powered by Waline v1.6.0


才怪

网络中的魔术师


文章分类
 * 学习园地
   (36)
 * 编程开发
   (8)
 * 算法之美
   (9)
 * 逆向工程
   (9)
 * CTF比赛
   (10)
 * 娱乐天地
   (22)
 * 奇思妙想
   (4)
 * 挑战智慧
   (9)
 * 魔术学堂
   (9)
 * 其它分类
   (10)
 * 博客折腾
   (4)
 * 故事小说
   (2)
 * 过期代码
   (4)

本文目录
 1. 一、插件需求
 2. 二、编写过程
 3. 三、下载地址





PoweredHexo
ThemedVolantis
AnalysedClarity

Copyright © 2012-2021 破博客