起因

经常看各类 javadoc 发现有一类 doc 并没有被做成标准的 doc 格式,直接复制出来想翻译一下,需要做一些预处理,比如删除注释、合并断行,前者各种编辑器的列模式搞定,后者就坑爹了,之前是手工一行一行的删除换行符,然后加空格的,非常坑爹。对于这类重复性操作,使用 vim 的宏录制就再好不过了。

vim 的宏录制

宏录制是指将一个操作序列保存后重复回放的功能。分为启动宏录制、进行宏录制、结束宏录制、使用宏录制四个部分。

启动宏录制 进行宏录制 结束宏录制 使用宏录制
normal 模式下,q+储存器名,比如按 qa 正常操作即可,需要注意可重复性 按 q @+存储器名,比如@a,如果想重复多次,可以 count+@+存储器名,比如 100@a,就会将操作序列 a 重复 100 次

示例:预处理 CompletableFuture 的设计文档

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
* Overview:
*
* A CompletableFuture may have dependent completion actions,
* collected in a linked stack. It atomically completes by CASing
* a result field, and then pops off and runs those actions. This
* applies across normal vs exceptional outcomes, sync vs async
* actions, binary triggers, and various forms of completions.
*
* Non-nullness of field result (set via CAS) indicates done. An
* AltResult is used to box null as a result, as well as to hold
* exceptions. Using a single field makes completion simple to
* detect and trigger. Encoding and decoding is straightforward
* but adds to the sprawl of trapping and associating exceptions
* with targets. Minor simplifications rely on (static) NIL (to
* box null results) being the only AltResult with a null
* exception field, so we don't usually need explicit comparisons.
* Even though some of the generics casts are unchecked (see
* SuppressWarnings annotations), they are placed to be
* appropriate even if checked.
*
* Dependent actions are represented by Completion objects linked
* as Treiber stacks headed by field "stack". There are Completion
* classes for each kind of action, grouped into single-input
* (UniCompletion), two-input (BiCompletion), projected
* (BiCompletions using either (not both) of two inputs), shared
* (CoCompletion, used by the second of two sources), zero-input
* source actions, and Signallers that unblock waiters. Class
* Completion extends ForkJoinTask to enable async execution
* (adding no space overhead because we exploit its "tag" methods
* to maintain claims). It is also declared as Runnable to allow
* usage with arbitrary executors.
*
* Support for each kind of CompletionStage relies on a separate
* class, along with two CompletableFuture methods:
*
* * A Completion class with name X corresponding to function,
* prefaced with "Uni", "Bi", or "Or". Each class contains
* fields for source(s), actions, and dependent. They are
* boringly similar, differing from others only with respect to
* underlying functional forms. We do this so that users don't
* encounter layers of adaptors in common usages. We also
* include "Relay" classes/methods that don't correspond to user
* methods; they copy results from one stage to another.
*
* * Boolean CompletableFuture method x(...) (for example
* uniApply) takes all of the arguments needed to check that an
* action is triggerable, and then either runs the action or
* arranges its async execution by executing its Completion
* argument, if present. The method returns true if known to be
* complete.
*
* * Completion method tryFire(int mode) invokes the associated x
* method with its held arguments, and on success cleans up.
* The mode argument allows tryFire to be called twice (SYNC,
* then ASYNC); the first to screen and trap exceptions while
* arranging to execute, and the second when called from a
* task. (A few classes are not used async so take slightly
* different forms.) The claim() callback suppresses function
* invocation if already claimed by another thread.
*
* * CompletableFuture method xStage(...) is called from a public
* stage method of CompletableFuture x. It screens user
* arguments and invokes and/or creates the stage object. If
* not async and x is already complete, the action is run
* immediately. Otherwise a Completion c is created, pushed to
* x's stack (unless done), and started or triggered via
* c.tryFire. This also covers races possible if x completes
* while pushing. Classes with two inputs (for example BiApply)
* deal with races across both while pushing actions. The
* second completion is a CoCompletion pointing to the first,
* shared so that at most one performs the action. The
* multiple-arity methods allOf and anyOf do this pairwise to
* form trees of completions.
*
* Note that the generic type parameters of methods vary according
* to whether "this" is a source, dependent, or completion.
*
* Method postComplete is called upon completion unless the target
* is guaranteed not to be observable (i.e., not yet returned or
* linked). Multiple threads can call postComplete, which
* atomically pops each dependent action, and tries to trigger it
* via method tryFire, in NESTED mode. Triggering can propagate
* recursively, so NESTED mode returns its completed dependent (if
* one exists) for further processing by its caller (see method
* postFire).
*
* Blocking methods get() and join() rely on Signaller Completions
* that wake up waiting threads. The mechanics are similar to
* Treiber stack wait-nodes used in FutureTask, Phaser, and
* SynchronousQueue. See their internal documentation for
* algorithmic details.
*
* Without precautions, CompletableFutures would be prone to
* garbage accumulation as chains of Completions build up, each
* pointing back to its sources. So we null out fields as soon as
* possible (see especially method Completion.detach). The
* screening checks needed anyway harmlessly ignore null arguments
* that may have been obtained during races with threads nulling
* out fields. We also try to unlink fired Completions from
* stacks that might never be popped (see method postFire).
* Completion fields need not be declared as final or volatile
* because they are only visible to other threads upon safe
* publication.
*/

原文档如上所示,为了翻译软件友好,我们需要去除注释/**/,将断行还原成一行。

去除注释

control + v 进入列模式,shift + G选至最后一行,方向键调节,d 删除(如果还发现有少量注释,如法炮制一并删除即可)

清除注释

断行还原成一行

normal 模式qa, 定位到第二行,i 键进入插入模式,$定位到行首,backspace 删除,此时光标在首行末尾,空格一次(添加空格,防止连词),esc 键退出插入模式,q 键结束录制。此时操作序列已经录制完了,待处理一共 105 行,那么执行 104 次重复即可,所以输入 104@a, 因为有空行的存在,为了不破坏段的效果,这里需要计算好每段的行数-1 次重复,然后迅速定位到下一段(即 段行数-1@a),如法炮制即可。

断行还原成一行

效果如下

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

A CompletableFuture may have dependent completion actions, collected in a linked stack. It atomically completes by CASing a result field, and then pops off and runs those actions. This applies across normal vs exceptional outcomes, sync vs async actions, binary triggers, and various forms of completions.

Non-nullness of field result (set via CAS) indicates done. An AltResult is used to box null as a result, as well as to hold exceptions. Using a single field makes completion simple to detect and trigger. Encoding and decoding is straightforward but adds to the sprawl of trapping and associating exceptions with targets. Minor simplifications rely on (static) NIL (to box null results) being the only AltResult with a null exception field, so we don't usually need explicit comparisons. Even though some of the generics casts are unchecked (see SuppressWarnings annotations), they are placed to be appropriate even if checked.

Dependent actions are represented by Completion objects linked as Treiber stacks headed by field "stack". There are Completion classes for each kind of action, grouped into single-input (UniCompletion), two-input (BiCompletion), projected (BiCompletions using either (not both) of two inputs), shared (CoCompletion, used by the second of two sources), zero-input source actions, and Signallers that unblock waiters. Class Completion extends ForkJoinTask to enable async execution (adding no space overhead because we exploit its "tag" methods to maintain claims). It is also declared as Runnable to allow usage with arbitrary executors.
Support for each kind of CompletionStage relies on a separate class, along with two CompletableFuture methods:

* A Completion class with name X corresponding to function, prefaced with "Uni", "Bi", or "Or". Each class contains fields for source(s), actions, and dependent. They are boringly similar, differing from others only with respect to underlying functional forms. We do this so that users don't encounter layers of adaptors in common usages. We also include "Relay" classes/methods that don't correspond to user methods; they copy results from one stage to another.

* Boolean CompletableFuture method x(...) (for example uniApply) takes all of the arguments needed to check that an action is triggerable, and then either runs the action or arranges its async execution by executing its Completion argument, if present. The method returns true if known to be complete.

* Completion method tryFire(int mode) invokes the associated x method with its held arguments, and on success cleans up. The mode argument allows tryFire to be called twice (SYNC, then ASYNC); the first to screen and trap exceptions while arranging to execute, and the second when called from a task. (A few classes are not used async so take slightly different forms.) The claim() callback suppresses function invocation if already claimed by another thread.

* CompletableFuture method xStage(...) is called from a public stage method of CompletableFuture x. It screens user arguments and invokes and/or creates the stage object. If not async and x is already complete, the action is run immediately. Otherwise a Completion c is created, pushed to x's stack (unless done), and started or triggered via c.tryFire. This also covers races possible if x completes while pushing. Classes with two inputs (for example BiApply) deal with races across both while pushing actions. The second completion is a CoCompletion pointing to the first, shared so that at most one performs the action. The multiple-arity methods allOf and anyOf do this pairwise to form trees of completions.

Note that the generic type parameters of methods vary according to whether "this" is a source, dependent, or completion.

Method postComplete is called upon completion unless the target is guaranteed not to be observable (i.e., not yet returned or linked). Multiple threads can call postComplete, which atomically pops each dependent action, and tries to trigger it via method tryFire, in NESTED mode. Triggering can propagate recursively, so NESTED mode returns its completed dependent (if one exists) for further processing by its caller (see method postFire).

Blocking methods get() and join() rely on Signaller Completions that wake up waiting threads. The mechanics are similar to Treiber stack wait-nodes used in FutureTask, Phaser, and SynchronousQueue. See their internal documentation for algorithmic details.

Without precautions, CompletableFutures would be prone to garbage accumulation as chains of Completions build up, each pointing back to its sources. So we null out fields as soon as possible (see especially method Completion.detach). The screening checks needed anyway harmlessly ignore null arguments that may have been obtained during races with threads nulling out fields. We also try to unlink fired Completions from stacks that might never be popped (see method postFire). Completion fields need not be declared as final or volatile because they are only visible to other threads upon safe publication

一个更骚的操作

仔细观察发现,原文档和标准的 javadoc 非常相似,仅仅是开头少了一个*,如果在空行加上分段标签

,那岂不是直接可以使用 idea 渲染成标准 javadoc 了,美滋滋:

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* <p>
* Overview:
*<p>
* A CompletableFuture may have dependent completion actions,
* collected in a linked stack. It atomically completes by CASing
* a result field, and then pops off and runs those actions. This
* applies across normal vs exceptional outcomes, sync vs async
* actions, binary triggers, and various forms of completions.
*<p>
* Non-nullness of field result (set via CAS) indicates done. An
* AltResult is used to box null as a result, as well as to hold
* exceptions. Using a single field makes completion simple to
* detect and trigger. Encoding and decoding is straightforward
* but adds to the sprawl of trapping and associating exceptions
* with targets. Minor simplifications rely on (static) NIL (to
* box null results) being the only AltResult with a null
* exception field, so we don't usually need explicit comparisons.
* Even though some of the generics casts are unchecked (see
* SuppressWarnings annotations), they are placed to be
* appropriate even if checked.
*<p>
* Dependent actions are represented by Completion objects linked
* as Treiber stacks headed by field "stack". There are Completion
* classes for each kind of action, grouped into single-input
* (UniCompletion), two-input (BiCompletion), projected
* (BiCompletions using either (not both) of two inputs), shared
* (CoCompletion, used by the second of two sources), zero-input
* source actions, and Signallers that unblock waiters. Class
* Completion extends ForkJoinTask to enable async execution
* (adding no space overhead because we exploit its "tag" methods
* to maintain claims). It is also declared as Runnable to allow
* usage with arbitrary executors.
*<p>
* Support for each kind of CompletionStage relies on a separate
* class, along with two CompletableFuture methods:
*<p>
* * A Completion class with name X corresponding to function,
* prefaced with "Uni", "Bi", or "Or". Each class contains
* fields for source(s), actions, and dependent. They are
* boringly similar, differing from others only with respect to
* underlying functional forms. We do this so that users don't
* encounter layers of adaptors in common usages. We also
* include "Relay" classes/methods that don't correspond to user
* methods; they copy results from one stage to another.
*<p>
* * Boolean CompletableFuture method x(...) (for example
* uniApply) takes all of the arguments needed to check that an
* action is triggerable, and then either runs the action or
* arranges its async execution by executing its Completion
* argument, if present. The method returns true if known to be
* complete.
*<p>
* * Completion method tryFire(int mode) invokes the associated x
* method with its held arguments, and on success cleans up.
* The mode argument allows tryFire to be called twice (SYNC,
* then ASYNC); the first to screen and trap exceptions while
* arranging to execute, and the second when called from a
* task. (A few classes are not used async so take slightly
* different forms.) The claim() callback suppresses function
* invocation if already claimed by another thread.
*<p>
* * CompletableFuture method xStage(...) is called from a public
* stage method of CompletableFuture x. It screens user
* arguments and invokes and/or creates the stage object. If
* not async and x is already complete, the action is run
* immediately. Otherwise a Completion c is created, pushed to
* x's stack (unless done), and started or triggered via
* c.tryFire. This also covers races possible if x completes
* while pushing. Classes with two inputs (for example BiApply)
* deal with races across both while pushing actions. The
* second completion is a CoCompletion pointing to the first,
* shared so that at most one performs the action. The
* multiple-arity methods allOf and anyOf do this pairwise to
* form trees of completions.
*<p>
* Note that the generic type parameters of methods vary according
* to whether "this" is a source, dependent, or completion.
*<p>
* Method postComplete is called upon completion unless the target
* is guaranteed not to be observable (i.e., not yet returned or
* linked). Multiple threads can call postComplete, which
* atomically pops each dependent action, and tries to trigger it
* via method tryFire, in NESTED mode. Triggering can propagate
* recursively, so NESTED mode returns its completed dependent (if
* one exists) for further processing by its caller (see method
* postFire).
*<p>
* Blocking methods get() and join() rely on Signaller Completions
* that wake up waiting threads. The mechanics are similar to
* Treiber stack wait-nodes used in FutureTask, Phaser, and
* SynchronousQueue. See their internal documentation for
* algorithmic details.
*<p>
* Without precautions, CompletableFutures would be prone to
* garbage accumulation as chains of Completions build up, each
* pointing back to its sources. So we null out fields as soon as
* possible (see especially method Completion.detach). The
* screening checks needed anyway harmlessly ignore null arguments
* that may have been obtained during races with threads nulling
* out fields. We also try to unlink fired Completions from
* stacks that might never be popped (see method postFire).
* Completion fields need not be declared as final or volatile
* because they are only visible to other threads upon safe
* publication.
*/
void test() {

}

然后按control + j查看文档,哈哈:

渲染后的效果

一个更骚的操作PLUS

直接开头加上一个*,然后option + command + l 格式化文档,你会发现 idea 自动给你添加 p 标签,太爽了。

总结

vim 操作更加灵活,适应不同的格式化文本需求,不过针对笔者的 case,最简单的方法是:idea 里,新建一个方法,把要格式化的注释拷贝过去,首行添加一个*,格式化文档即可。

Comments