Kenny 肉桂的主页

记录自己的进步


  • 首页

  • 归档

  • 标签

  • 搜索
close

Vim实践Tips(三)

发表于 2016-07-21   |   分类于 其他技术   |  

Tip 10 使用计数做一些简单的计算

大多数命令模式下的指令能够和计数搭配使用.我们可以利用这个特性做一些简单的运算.

1
this character is 5

<C-a> 增加计数 (Ctrl+a)
<C-x> 减少计数 (Ctrl+x)
他们可以可数字搭配使用,例如:

1
this character is 16 " 10<C-a>

这个 如果是在数字字符上,那么就会给他增加数字.如果没有在数字上,那么它会在这行中查找数字,并且跳转到数字上.如果没有那么就不会做任何操作.

例如下面有一段 css 代码:

1
2
.blog, .news { background-image: url(/sprite.png); }
.blog { background-position: 0px 0px }

我们要复制最后一行,然后做一些改变:

  1. 把单词 blog 换成 news
  2. 把 0px 换成 -180px

实现1,可以使用 yyp 然后使用 cw 修改单词.
那么2怎么实现呢?

第一种方式是: f0, 然后 i 进入插入模式,输入-18,然后<Esc>
但是我们的光标不在数字上,那么需要额外的跳转.而 <C-x> 可以自动给我们找到数字.
所以,直接 180<C-x> 更快

1
.blog { background-position: -180px 0px } "180<C-x>

Tip 11 如果可以重复,就别计数

我们可以通过提供个数字来减少完成特定任务所需要的按键.但是这不代表我们就该这么做.还是应该思考下到底该重复还是该计数.

假设我们有下面的文字:

1
Delete more than one word

d2w 和 2dw 都能完成任务.

  • d2w 是d, 然后加上2w 的 motion ,理解为: 删除两个单词
  • 2dw是2次执行 dw ,理解为: 删除一个单词,执行两次

现在让我们想想一个替换方案: dw. 删除一个单词,然后重复之.

讨论几种方式.

其实d2w和2dw 没有区别,如果执行之后,按 u ,都会恢复两个单词.如果按dot,将重复删除后两个单词.
如果我们要删除下一个单词(总共三个)那我们就需要先u(恢复两个单词),然后d3w.这还是比较麻烦的.
dw. 按u,会恢复一个单词,如果删除下个单词,只需要重新按dot即可.
在这种情况下,重复的优势更明显.

如果我要删除6个单词呢? 我可以 d6w 或者6dw.或者 dw..... ,当然,前者有更少的按键.但是有个问题在这:我们需要数一下单词的数量,而且如果错误了,u会恢复6个单词.而dw.....如果出现错误,u一下,只是恢复一个单词.我们可以更好的控制这个过程.

记住我们的”咒语”: 操作,重复,撤销.

必要时使用计数

下面的文字,如果我要把 a couple of 换成 some more.

1
2
I have a couple of questions.
I have some more questions. "按键依次是 c3wsome more

在这个场景下,使用dot命令没有什么意义.即使重复了,最后还要按i进入插入模式.这样太笨拙了,所以我还是愿意使用计数.

计数还有个好处,就是能够有个条理清楚的恢复操作.比如我d3w,u就会恢复3个单词

Tip 12 征服结合命令

Vim的强大源于操作符和移动命令的结合.

操作符+移动=操作

d{motion} 可以使用dl删除一个字符,daw删除整个单词,dap删除整段.
c{motion} 和 y{motion}和上面类似

操作符和移动的结合,可以认为是一种语法.第一条规则很简单:一个动作由一个操作符和一个移动组成.学习新的操作符就像学习Vim的词汇表.只要我们遵循简单的语法,随着词汇量增加,我们就能表达更多想法.

假设我们已经知道了通过 daw 删除一整个单词.然后,我们学到了 gU,这也是一个操作符.所以,我们就能通过gUaw把当前单词转换成大写.

再假设我们知道了ap(一整段motion},然后我们就能合成新的操作:
dap 删除一整段 gUap 让一整段大写.

Vim 的语法还有个规则:如果一个操作符被重复输入,那么motion就等于当前行.例如:
-dd 删除当前行
->> 缩进当前行
-gUgU 或者 gUU 大写当前行 g是后面操作符的一个前缀

Vim的操作符命令

1
2
3
4
5
6
7
8
9
10
11
操作符        效果
c Change 改变
d Delete 删除
y Yank into register 复制到寄存器
g~ Swap case 切换大小写
gu make lowercase 小写
gU make upppercase 大写
> shift right 右移
< shift left 左移
= autoindent 自动缩进
! Filter {motion} lines through an external program

拓展Vim整合的力量

Vim标准的操作符相对来说比较少,但是我们可以定义新的.

使用现有的操作符自定义移动

Vim标准的移动命令已经很全面,但是我们还可以增加新的移动和文本对象.

待决模式

除了明显的插入,命令和底行模式.Vim还有些容易被忽略的模式.待决模式( Operator-Pending mode )就是其中的一个.我们每天都大量使用它,但是每次都持续一小段时间.例如dw,这个模式仅仅持续了你按下d到按下w这中间的这个时间.

如果我们把Vim看做是一个有限状态机.那么待决模式就是仅接受移动命令的状态.当一个操作符被触发的时候,这个状态被激活,在输入移动命令之前,Vim不会做任何操作.当待决模式被激活后,我们可以通过就可以中断,返回命令模式.

Vim实践Tips(二)

发表于 2016-07-19   |   分类于 其他技术   |  

Tip 5 手动查找和替换

下面每一行中都有 content 这个单词

1
2
3
4
5
6

...We're waiting for content before the site can go live...

...If you are content with this, let's go ahead with it...

...We'll launch as soon as we have the content...

如果我们想把所有的 content 替换成 copy, 那么可以很简单的想到替换命令.

1
2

:%s/content/copy/g

但是有时候我们并不想全局替换掉.

懒惰点:不做输入的查找

你也许已经猜到.是我最喜欢的单键Vim命令.第二喜欢的是 *,它可以搜索处于光标下面的单词.

1
2
3
4
5
6

...We're waiting for copy before the site can go live...

...If you are copy with this, let's go ahead with it...

...We'll launch as soon as we have the content...

首先将光标置于 content 上面,然后用*命令去查找它,这时候将发生两个事情:

  1. 光标将跳转到下个匹配处(即下个 content 单词)

  2. 所有出现匹配项的地方将高亮显示 (如果没有,使用 :set hls .

上面两件事情发生之后,我们就可以使用 n 命令跳转到下一个.这时候,使用 *nn 可以循环所有匹配,然后光标转到我们开始进行搜索的地方

让更改变得可重复

当我们的光标置于 content 的开始位置的时候,我们准备去更改它.这包含两个步骤:

  1. 删除单词 content

  2. 输入修改的内容. cw 删除到单词结尾命令,并且进入插入模式.

然后我们输入 copy 这个单词. Vim 将记录我们的键盘点击,直到我们离开插入模式,所以, cwcopy<Esc> 将会被记录为一个单个命令.通过使用.就可以重复上面的操作.

Tip6 Dot公式

在 Tip2中,我们试着将每个句子后面加; 最后,我们通过 j. 进行重复操作.

在 Tip3中,我们将每个+前后添加空格. 最后,我们通过 ;. 进行重复操作

在 Tip5中,我们将 content 替换成 copy,最后,我们通过 n. 进行重复操作.

理想的状态: 一个按键负责移动,一个按键负责执行操作.

在上面所有的操作中 . 重复最后的更改.这不是他们全部的共同点,我们都还用了一个键去移动光标.这已经是一个不能再好的情况了.我们在将来的编辑中,可以反复看到这个编辑模式.为了方便,我们把这个模式成为 Dot公式 (Dot Formula)

Tip7 拿开你的笔刷

Normal Mode (命令模式) 可以类比为一个画家,把笔刷离开画布.这时候,他可以休息,可以构思.同理,程序员也可以在 Normal Mode 中进行思考,组织自己的思路.当我们要改变的时候,也不用非得进入插入模式.在 Normal Mode中,我们可以格式化我们的代码,复制,或者移动他们.

Tip8 强化你的撤销

在其他编辑器中,通过在输入一些东西之后进行撤销,可以撤销我们最后输入的单词或者字符.然后在 Vim 中,我们设置可以调整撤销命令的粒度.

u 这个命令可以触发撤销命令.它可以撤销包括Normal,Visual还有 Command-Line 模式的更改.当然,也包括在插入模式下的文本输入或者删除.所以我们可以说: i{ 插入一些更改}< Esc> 构成了一个改变. 然后一次u 就可以撤销这个改变.

另外,插入模式中,如果使用了上下左右箭头,那么就相当于在 NormalMode下使用了 hjkl.区别就是我们不用离开插入模式,但是这些操作,会被记录到点公式 (Dot Fomula)中.

Tip9 创建可重复的改变

vim将重复操作进行了优化,为了利用这个特性.我们需要留心怎么创建可重复的改变

在 Vim 中,做一件事通常有很多方式.但是衡量”好”的方式的机制就是:更少的键盘敲击.

假设我们的光标在 h 这个字母上,我们想要删除单词 nigh

1
2

The end is nigh

1. 向后删除

1
2
3
4
5
6

The end is nigh "开始

The end is h "db 从光标位置删除单词的前面部分

The end is "x 删除当前光标的字符

2. 向前删除

1
2
3
4
5
6

The end is nigh "开始

The end is nigh "b 向后移动光标一个单词

The end is "dw 向前删除一个单词

3. 删除整个单词

上面两个解决方案都牵涉到了一些准备工作,例如移动.其实,利用aw 命令可以更精准高效的完成我们的需求

1
2
3
4

The end ais nigh "开始

The end is "daw

4. 哪一个是最可重复的

上面我们使用了三种方式进行删除一个单词.每种方式中,我们都是按了三个键,那么那种方式是更好的呢?

记住, Vim 优化了重复.那么检验好坏的标准就是重复.下面使用dot 命令来检验三种方式,通过测试发现:

  • 第一种方式: . 等价于 x (db 是改变操作. x 也是改变操作)

  • 第二种方式: . 等价于 dw (b 是纯移动, dw 是改变操作)

  • 第三种方式: . 等价于 daw (daw是改变操作)

看起来2 3 都是挺有用的,但是有个细节 2删除一个单词,但是不会删除对应的空格,表象上来看就是不会移动光标到下个单词上,那么这时候, .这个命令就没什么意义. 3 会把要删除的单词附带空格删除,同时光标停留在 is 的结尾.那么.这个操作就能继续删除一个单词. (我强烈建议自己动手试试看)



Vim实践Tips(一)

发表于 2016-07-18   |   分类于 其他技术   |  

Tip 1 dot 命令

说明: . dot 重复上个命令的使用

1
2
3
4
5
6
7
line one

line two

line three

line four

x :删除当前光标下的字符

1
2
3
4
5
6
7
 one " x . . .  x 删除, . 重复

line two

line three

line four

如图:
dot 命令的使用

几个小提示:

:set nu 显示行号 :set nonu 关闭行号显示

显示和关闭行号

:3,5 co 8 将9到12行的内容输出到8行

输出范围到领一行

:3,5 de 删除3到5行的内容

删除范围

>G 增加从当前行到文件末尾所有行的缩进.同理,使用 . 可以重复增加缩进

重复缩进

还可以利用 j. 做成下面的布局

1
2
3
4
5
6
7
line one

line two

line three

line four

梯形缩进

Tip 2 不要重复

例如,我们想要在下面所有的行后面加一个分号

1
2
3
4
5
var foo = 1

var bar = 'bar'

var foobar = foo + bar

使用 $ 移动到行末尾,a追加然后输入; ,然后按<Esc>返回命令模式.这算完成了第一行

如果对下面两行也应用这个,就应该: j$.

1
2
3
4
5
var foo = 1;

var bar = 'bar'; "j$.

var foobar = foo + bar; "j$.

虽然这样也能完成,但是还是差点意思.还是有提升空间的.

减少无关的移动

a 是在当前光标位置后面追加,并自动切换到插入模式

A 是在当前行末进行追加,并自动切换到插入模式 相当于 $a

1
2
3
4
5
var foo = 1;	" A;<Esc>

var bar = 'bar'; " j.

var foobar = foo + bar; " j.

d 删除,不能单独用,得跟后续操作符,比如 dd 是删除一整行,d$ 是删除直到行的末尾

x 删除当前光标下的单个字符

c 跟 d 类次,但是删除完成后会进入插入模式

c 和 d 都要加入motion motion类似是 w b 等这些

23,35 co 66 复制

23,35 m 66 剪切

23,35 de 删除

几个一个顶俩的快捷键

C c$ 删除到行末尾,并进入插入模式

s cl 替换当前字符: c加motion,l 一个字符

S ^C 删除整个行 ^移动到行首,C删除整行

I ^i 到行首进行插入

A $a 到行尾进行插入

o A<CR> 进入下一行,并进入插入模式 是回车的意思

O ko 进入上一行,然后插入

Tip 3 退一步,进三步

foo = "method("+argument1+","+argument2+")";```objc
1

上面的代码看着不太舒服,因为在我们印象中,加号两边应该有空格.那么我们来看怎么以Vim的方式完成这个任务:

`f+` 查找最近的`+` , `s` 替换`+` 为 `空格+空格`

```var foo = "method(" + argument1+","+argument2+")";

对于后面的,我们当然可以使用 f+ 然后 . 重复替换,完成任务.

但是这里有个新的操作符 ; 这个 ; 可以重复执行最近的查找操作.f+就是一个查找操作.所以,对于后面的+ ,我们可以通过 ;. 依次完成替换.

Tip4 操作,重复,撤销

通过以上的几个tip,我们学会了,先操作,然后另其重复执行,借此完成一些重复任务.

但是有时候,我们可能在反复的重复操作中,按多了.例如 tip2 中的 j.j.j. 很可能顺序按错了. 如果出现错误,那么我们就可以在出错的时候按 u 来撤销操作.又或者,Tip3中的;按多了(意味着移动的太过了)那么可以使用,来跳回去.

通过以上的描述,能看出来,不同的误操作,对应着不同的撤销方式.下面是个参考表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
意图				操作				重复		撤销

改变点东西 {edit} . u

行内查找下个字符 f{char}/t{char} ; ,

行内查找前一个字符 F{char}/T{char} ; ,

在文档内查找下个匹配 /pattern<CR> n N

在文档内查找前个匹配 ?pattern<CR> n N

执行替换 :s/target/replacement & u

执行一系列改变 qx{changes}q @x u

f 和 t 的区别是 f 停留光标在查找字符,t光标停留在查找字符之前

视频裁剪

发表于 2016-07-14   |   分类于 视频相关   |  

AVAsset

AVAsset是一个表现音视频媒体的抽象类.AVAsset对象给我们开发提供了媒体文件的访问接口.
这个 AVAsset 可以通过文件创建,也可以是来自用户相册目录的.如果获得了一个视频文件的 AVAsset,我们就可以从中获取静态图片,转换格式,或者是裁剪内容.

通过以下代码,获得特定位置的视频文件:

1
NSString * videoPath = @"a video file path";
AVAsset *anAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:videoPath] options:nil];
```objc
其中 options 是一个字典,这个字典只有一个 key-value:
`AVURLAssetPreferPreciseDurationAndTimingKey` value 是 `YES` 或者 `NO`

这个是设置时间精确度的,如果设置为 YES, 那么会造成很大的开销,但是可以保证操作的精度,对于我的裁剪操作,不用设置.因为我的业务中,裁剪范围是用户滑块操作的,本来精度就要求不高.
传递 nil 和 传递 NO, 两者等效.
特别的,当进行视频合成操作的时候,需要设置这个字典,并将 value 设置为 `YES`,因为如果精度不够,可能造成音视频不同步等问题.

### AVAssetExportSession

AVAssetExportSession 是一个控制 Asset 异步导出的对象.可以实现裁剪视频,转换格式等需求. 代码如下:

exportSession_ = [[AVAssetExportSession alloc]
initWithAsset:anAsset presetName:AVAssetExportPreset960x540]

1
2
3
4

这个`presetName` 是系统提供的预设,有一些常用的视频分辨率和视频质量控制的选项.可以按住`command`自行查看.另外.如果预设的分辨率不能满足需求,我们还可以自定义任意分辨率,这个将在我以后的文章中进行说明.

然后就是配置`AVAssetExportSession`,下面分别配置了`导出路径`,`导出文件格式`,`截取范围`:

exportSession.outputURL = tempVideoURL;
exportSession
.outputFileType = AVFileTypeMPEG4;
exportSession_.timeRange = [self videoTimeRange:anAsset];

1
需要说明的是这个截取范围的实现:

-(CMTimeRange)videoTimeRange:(AVAsset*)anAsset{
CMTime start = CMTimeMakeWithSeconds(self.videoRange.startTime, anAsset.duration.timescale);
CMTime duration = CMTimeMakeWithSeconds(self.videoRange.duration, anAsset.duration.timescale);
CMTimeRange range = CMTimeRangeMake(start, duration);
return range;
}

1
2
3
4
5
`CMTime` 是一个结构体对象,常用的两个值是: `value` 和 `timescale`. 两者的关系可以表示为: `value/timescale=seconds`.

在上面的方法中,我将来自滑块的值(秒为单位),转换成了`CMTime`然后构造了一个` CMTimeRange` 对象.

最后进行导出:

[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession
.status) {
case AVAssetExportSessionStatusUnknown: {

            break;
        }
        case AVAssetExportSessionStatusWaiting: {

            break;
        }
        case AVAssetExportSessionStatusExporting: {

            break;
        }
        case AVAssetExportSessionStatusCompleted: {

            break;
        }
        case AVAssetExportSessionStatusFailed: {

            break;
        }
        case AVAssetExportSessionStatusCancelled: {

            break;
        }
    }
}];

```objc

可以对各种状态进行判断.进而采取不同的操作.通常关心的是Failed 和Completed ,前者给用户提示,后者进行后续操作.

到此,就完成了一段视频的裁剪操作.

一个React Native项目-一些注意点

发表于 2016-07-02   |   分类于 React Native   |  

对http网络请求的支持

由于在iOS9开始,Apple强制了https的请求.但是如果服务器还不支持,那么应该在plist中添加以下字段:
29000QQ20160901-2.png

这步要注意,ReactNative并没有聪明替你配置好这个iOS的环境,我是在各种网络请求都异常后,才发现的这个问题.

提取文件

因为要同时支持iOS和Android, 那么我们就不应该将布局代码写到index.android.js或者index.ios.js中,当然也不应该写好一个,然后copy到另一个,无论怎么说,如果分散,我们将面临维护多份代码的窘境.所以好的方式是,将实现提取出来,在index.android.js和index.ios.js中,只保持对接口文件的引用.类似下面:

1
2
3
4
5
6
7
class GUIShopping extends Component {
render() {
return (
<Main/>
);
}
}

Android的启动页面

Android本身没有像iOS那么方便的配置启动页的方式,原生的方式是通过Activity来制造假象,同理,利用ReactNative还是要做这个处理.
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
class GUIShopping extends Component {
render() {
return (
<Navigator
initialRoute={{name:'启动页',component:LaunchImage}}
configureScene={()=>{ return Navigator.SceneConfigs.PushFromRight; }}
renderScene={(route,navigator)=>{
let Component = route.component;
return <Component {...route.passProps} navigator={navigator}/>
}} />
);
}
}

而LaunchImage就是一个普通的Component,里面有个定时器,在规定时间内切换到主页,看起来效果和iOS是一样的,主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class LaunchImage extends Component {
render() {
return (
<Image source = {{uri:'launchimage'}} style={styles.launchImage}/>
);
}

componentDidMount() {
setTimeout(()=>{
//页面的切换
this.props.navigator.replace({
component:Main,
});
},2000);

}
}

ListView横向排版的实现

默认的ListView是和iOS的TableView类似的,也就是上下滑动,如果想要实现类似CollectionView的布局效果,那么需要做一些配置:

1
2
3
4
5
6
7
8
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
contentContainerStyle={styles.contentView}
scrollEnabled={false}
>

</ListView>

contentView的实现如下:

1
2
3
4
5
contentView:{
flexDirection:'row',
flexWrap:'wrap',
width:width,
},

要点:

  1. 要指定ListView的宽度
  2. cell应该具备宽高(特别坑)

    其中第二条没有发现有资料提及,但是自己编码的时候发现,只有设置好cell的宽度和高度,才能实现预想的效果.
    最终效果如下:

    93550QQ20160901-3.png

一个React Native项目-项目介绍

发表于 2016-07-01   |   分类于 React Native   |  

背景

从ReactNative诞生的那天开始,就对它非常关注.一方面是欢喜可以有个靠谱的方案来实现跨平台开发了,另一方面也是担心它虎头蛇尾.好在,到现在看来,它势头还是很猛的.

现在接触ReactNative也有一定时间了,知识比较零散,所以想借助一个练手项目来串一下知识,粗略的模仿了美团的客户端.

项目使用ES6语法 ,最终效果如下:

32248shopping.gif

代码

代码已经开源到 github

说明

因为代码已经上传,所以就不在赘述,主要分开说说一些注意点.这些我将分文章阐述.

一些资料

Reat Native中文官网 这上面关于环境配置和基础控件的使用都非常全面,是必不可少的参考资料.

Flexbox ReactNative中大量使用了Flexbox进行布局,所以这方面的知识必不可少

11款ReactNative开源组件 研究别人的代码是一种非常好的提升方式

1234…13
桂庆

桂庆

Kenny 肉桂的主页 记录自己的进步

75 日志
17 分类
23 标签
RSS
微博
© 2013 - 2017 桂庆
由 Hexo 强力驱动
主题 - NexT.Mist