分类目录归档:未分类

Android平板安装Termux和LunarVim

这次趁着双11买了个小米平板5pro,才发现不过是大号手机而已,系统是基于Android 11的MIUI 13。除了WPS,bilibili、浏览器都不过兼容桌面模式而已,然而却又失去了移动设备的便利性:touch事件不能精确响应,于是卸掉重新安装的普通版。终于体会到了雪球不明真相群众的那句话:平板上的东西已经在手机上进化完了。想想这个平板除了刷视频、看书、画画,还能干点啥?看代码应该也有优势,毕竟分辨率还不错。Android上并没有什么好用的代码App,虽然可以安装Github查看代码,但还是看不了几行,也不如IDE来的方便。幸好还有Termux,极大的拓展了Android的可用性,增加了超过1万个cli应用,比如比应用市场上任何服务器连接App都好用的ssh,强大的编程开发工具LunarVim
Termux是一个Android终端(terminal)模拟软件并提供Linux环境,可以安装许多Linux下常见软件,比如ssh、git、curl,和各种开发软件,比如nodejs、python、rust、golang等等。Termux既可以从GitHub上下载安装,也可以使用F-Droid安装。使用F-Droid的好处在于可以自动更新,和管理其他的扩展,比如Termux:Styling、Termux:API。安装完成后记得给予联网权限,如果安装了其他的扩展,记得在安全中心-联网管理中找到对应的扩展App也给予联网权限,否则Termux就上不了网。 安装完成后打开Termux,这里注意Termux重置了目录,所有目录都是在data/data/com.termux/files/下面,并提供了两个快捷访问$HOME: data/data/com.termux/files/home和$PREFIX: /data/data/com.termux/files/usr。运行下面的命令设置一下存储和文件夹软链接,这样方便Termux与外部目录(比如Downloads)互相复制粘贴

termux-setup-storage

也可以更改一些配置,比如软键盘快捷键之类的

vim ~/.termux/termux.properties
#重新加载配置
termux-reload-settings
#更改使用的源仓库,默认使用多仓库,可以改为使用单一仓库,比如清华源
termux-change-repo

然后安装一些基础软件

pkg install openssh git curl wget vim bat croc

然后安装oh-my-zsh和自动补全插件,其他插件的安装与正常安装无差别

pkg install zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

然后编辑~/.zshrc,更改主题和插件

# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
#ZSH_THEME="robbyrussell"
ZSH_THEME="agnoster"

# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(git zsh-autosuggestions)

如果zsh显示乱码的话,可以按住屏幕在弹出的more菜单里面更改nerd font字体,比如ubuntu。
现在可以开始安装LunarVim的依赖

pkg install neovim build-essential python vim-python nodejs rust fd ripgrep

安装完成完成后neovim, make,npm,pip,cargo也都安装好了。这时候就可以使用nvim来编辑了,可以参考:help nvim/:Tutor进行学习。这里顺便安装了pyhon vim的交互包,等下可以跳过python依赖的安装。还安装了两个rust写的神器:文件查找fd和文件内容搜索ripgrep,等下也可以跳过rust依赖安装。,
LunarVim是一个基于Neovim开发的IDE,打包了文件搜索、内容查找、代码补全,语法高亮等许多功能,这个可比简单vim强多了,更多功能、特点可以在官网视频学习。官方提供的安装脚本并不包含Termux的,我们下载下来看一下是否都已经安装好依赖、做一些改动

curl https://raw.githubusercontent.com/lunarvim/lunarvim/master/utils/installer/install.sh > install.sh

这里稍微改一下,匹配不到OS就使用pkg安装

function detect_platform() {
  case "$OS" in
    Linux)
      if [ -f "/etc/arch-release" ] || [ -f "/etc/artix-release" ]; then
        RECOMMEND_INSTALL="sudo pacman -S"
      elif [ -f "/etc/fedora-release" ] || [ -f "/etc/redhat-release" ]; then
        RECOMMEND_INSTALL="sudo dnf install -y"
      elif [ -f "/etc/gentoo-release" ]; then
        RECOMMEND_INSTALL="emerge -tv"
      else # it's termux
        RECOMMEND_INSTALL="pkg install -y"
      fi
      ;;

然后开始安装LunarVim

chmod +x install.sh
export LV_BRANCH='release-1.2/neovim-0.8'
./install.sh
      88\                                                   88\
      88 |                                                  \__|
      88 |88\   88\ 888888$\   888888\   888888\ 88\    88\ 88\ 888888\8888\
      88 |88 |  88 |88  __88\  \____88\ 88  __88\\88\  88  |88 |88  _88  _88\
      88 |88 |  88 |88 |  88 | 888888$ |88 |  \__|\88\88  / 88 |88 / 88 / 88 |
      88 |88 |  88 |88 |  88 |88  __88 |88 |       \88$  /  88 |88 | 88 | 88 |
      88 |\888888  |88 |  88 |\888888$ |88 |        \$  /   88 |88 | 88 | 88 |
      \__| \______/ \__|  \__| \_______|\__|         \_/    \__|\__| \__| \__|

--------------------------------------------------------------------------------
Detecting platform for managing any additional neovim dependencies
--------------------------------------------------------------------------------
Would you like to install LunarVim's NodeJS dependencies?
[y]es or [n]o (default: no) : y
Installing node modules with npm..
All NodeJS dependencies are successfully installed
--------------------------------------------------------------------------------
Would you like to install LunarVim's Python dependencies?
[y]es or [n]o (default: no) : y
Verifying that pip is available..
/usr/bin/python3: No module named ensurepip
Installing with pip..
Requirement already satisfied: pynvim in /usr/lib/python3/dist-packages (0.4.2)
All Python dependencies are successfully installed
--------------------------------------------------------------------------------
Would you like to install LunarVim's Rust dependencies?
[y]es or [n]o (default: no) : y
All Rust dependencies are successfully installed

这里注意,除了NodeJS依赖需要安装,Python、Rust都已经安装好了,选择No就可以了。安装完成后可以使用命令打开

#打开默认窗口
lvim
#打开指定文件
#lvim install.sh
#打开指定目录
#lvim downloads

默认界面长这样子,可以搜索文件、搜索内容,打开文件、项目等。如果有出现文字、图标显示乱码,那么需要安装nerd font,参考上面的字体配置。

按下空格键就会出现引导界面

比如空格+e打开目录

空格+s搜索

空格+L打开LunarVim配置,比如keyMaps

剩下就是neovim、LuarVim的操作了,比如ctrl+h/ctrl+l的文件目录与代码窗口左右切换,空格+b+p/n/e/j在打开的文件里面切换、打开、关闭,alt+1/2/3打开下边、右边、弹出窗口里面打开终端



如此便可以使用LunarVim写代码了。基于Neovim的编辑器还有NvChadSpaceVim,也都非常强大,不过LunarVim默认配置了许多开箱即用的功能。另外,还可以使用code server,不过这个方案直接安装是不可以,需要借助proot-distro安装其他Liunx才可以。如果Termux不能满足你的需求,可以使用proot-distro安装一个Linux来进一步模拟。如果觉得Termux好用的话,可以给它捐款

参考链接:
Termux wiki
Termux 高级终端安装使用配置教程

PHP yield应用

PHP 5.5开始新增了神奇的关键字yield,能够从生成器(generators)中返回数据。yield有点像普通函数中的关键字return,但是不会彻底停止函数的执行(普通函数一旦return便不执行了),可以暂停循环并返回值,每一次调用便从中断处继续迭代。生成器可以用于替代循环迭代,每一次调用返回一个生成器对象(generator)

yield能够延迟执行,可以用于对大量数据进行迭代而不用预先在内存中生成数组。例如动态生成一个大数组:

<?php
function xrange($start, $end, $step = 1) {
    for ($i = $start; $i <= $end; $i += $step) {
        yield $i;
    }
}

foreach (xrange(1, 1000000) as $num) {
    echo $num, "\n";
}

$range = xrange(1, 1000000);
var_dump($range); // object(Generator)#1
var_dump($range instanceof Iterator); // bool(true)

利用yield简便、高效的生成fibonacci数列而不是循环或递归

<?php
function fibonacci($count) {
    $prev = 0;
    $current = 1;

    for ($i = 0; $i < $count; ++$i) {
        yield $prev;
        $next = $prev + $current;
        $prev = $current;
        $current = $next;
    }
}

foreach (fibonacci(48) as $i => $value) {
    echo $i , ' -> ' , $value, PHP_EOL;
}

利用yield来循环读取文件,而不需要像file函数那样一次性加载进来,节省内存

<?php
function file_lines($filename) {
    $file = fopen($filename, 'r'); 
    while (($line = fgets($file)) !== false) {
        yield $line; 
    } 
    fclose($file); 
}
 
foreach (file_lines('somefile') as $line) {
    // do some work here
}

yield除了能够返回值,用作变量时还可以接收值。

<?php
function logger($fileName) {
    $fileHandle = fopen($fileName, 'a');
    while (true) {
        fwrite($fileHandle, yield . "\n");
    }
}

$logger = logger(__DIR__ . '/log');
$logger->send('Foo');
$logger->send('Bar');

由于yield具有中断执行后再次调用又可以从中断处执行,外界又可以通过生成器对象(generator)的send方法进行交互,可以用于协程(coroutine),作多任务协作的流程控制。这里有个例子

<?php
class Task {
    protected $taskId;
    protected $coroutine;
    protected $sendValue = null;
    protected $beforeFirstYield = true;

    public function __construct($taskId, Generator $coroutine) {
        $this->taskId = $taskId;
        $this->coroutine = $coroutine;
    }

    public function getTaskId() {
        return $this->taskId;
    }

    public function setSendValue($sendValue) {
        $this->sendValue = $sendValue;
    }

    public function run() {
        if ($this->beforeFirstYield) {
            $this->beforeFirstYield = false;
            return $this->coroutine->current();
        } else {
            $retval = $this->coroutine->send($this->sendValue);
            $this->sendValue = null;
            return $retval;
        }
    }

    public function isFinished() {
        return !$this->coroutine->valid();
    }
}

class Scheduler {
    protected $maxTaskId = 0;
    protected $taskMap = []; // taskId => task
    protected $taskQueue;

    public function __construct() {
        $this->taskQueue = new SplQueue();
    }

    public function newTask(Generator $coroutine) {
        $tid = ++$this->maxTaskId;
        $task = new Task($tid, $coroutine);
        $this->taskMap[$tid] = $task;
        $this->schedule($task);
        return $tid;
    }

    public function schedule(Task $task) {
        $this->taskQueue->enqueue($task);
    }

    public function run() {
        while (!$this->taskQueue->isEmpty()) {
            $task = $this->taskQueue->dequeue();
            $task->run();

            if ($task->isFinished()) {
                unset($this->taskMap[$task->getTaskId()]);
            } else {
                $this->schedule($task);
            }
        }
    }
}
function task1() {
    for ($i = 1; $i <= 10; ++$i) {
        echo "This is task 1 iteration $i.\n";
        yield;
    }
}

function task2() {
    for ($i = 1; $i <= 5; ++$i) {
        echo "This is task 2 iteration $i.\n";
        yield;
    }
}

$scheduler = new Scheduler;

$scheduler->newTask(task1());
$scheduler->newTask(task2());

$scheduler->run();

有些任务是需要交互进行的,如socket的监听和回复;有些任务异步执行又需要回调,如A执行不阻塞程序,但B执行又取决于A是否执行完毕。这些都可以使用yield来进行封装,达到流程控制的目的。

参考链接:
Generators overview
What does yield mean in PHP?
What is the difference between a generator and an array?
Cooperative multitasking using coroutines (in PHP!)
What Generators Can Do For You
Generators and Coroutines in PHP
Generators in PHP
协程与yield
http://www.hitoy.org/coroutine-and-yield.html
Co-operative PHP Multitasking
Generator (computer programming)
异步处理在分布式系统中的优化作用

使用PC控制android手机

跑步的时候不小心把手机屏幕摔裂了,操作不了。在等待新手机的时候,又没有其他手机可以用。于是想用电脑来控制手机,这里推荐一个软件Total Control,可以在用鼠标代替手指操作手机,也可以用于手机截屏、演示等。

首先到官网下载Total Control 最新的PC版软件。安装时会提示下载Java环境,安装完Java后,可以开始安装Total Control了。

Total Control通过USB连接手机需要驱动,这里推荐一个懒人方法:通过豌豆荚自动识别你的手机并安装驱动,然后Total Control也可以连接手机了,会自动安装Total Control手机端 ,然后就可以开始玩了。 继续阅读

Mysql INT和CHAR类型的隐式转换

最近碰到一个问题,由于没有对参数进行过滤和转换,直接拿到mysql里面进行查询了,大概是这样的:

select * from store where id='1}';
select * from store where id='{1}';#测试

但是前者仍然可以查出id为1的记录,后者是不行。知道mysql有隐式转换却不知道具体是怎么样的。google了下,发现隐式转换还有其他的问题,例如:

select * from store where name=0;
select * from store where name='0';

前者将会查询出所有的记录,而后者只会匹配name值为0的记录。
总结了一下大概是这些大概是以下的原因:

  • 当查询字段是INT类型,如果查询条件为CHAR,将查询条件转换为INT,如果是字符串前导都是数字将会进行截取,如果不是转换为0。
  • 当查询字段是CHAR类型,如果查询条件为INT,将查询字段为换为INT再进行比较,可能会造成全表扫描。示例2的name字段为CHAR类型,第一句查询转换为INT时都等于0,所以全部匹配了;第二句查询同为CHAR类型不发生转换,所以仅匹配值为0的记录。

mysql的隐式转换还有很多其他的坑,所以一定要指明查询条件类型,不要让mysql去做自动转换。

参考链接:
价值百万的 MySQL 的隐式类型转换
mysql字符串的隐式转换导致数据库操作异常
关于mysql 隐式转换的一个小问题
MySQL查询类型不正确不使用索引?
mysql的隐式的数据类型转换
MySQL隐式转换之坑
列类型

Windows 8 安装Vagrant和VirtualBox

由于php的一些扩展只有在linux下面才能用,就算是Cygwin下面也不行,例如pcntl。所以就决定安装一个linux虚拟机来作为开发环境,顺带找到了另外一个东西:Vagrant。Vagrant作为一款虚拟机环境统一配置管理工具,后端可以是VirtualBox,VMWare,AWS。这样当运行环境配置完了可以方便的部署在其他机器上或给予其他开发人员,实现配置一次,到处运行的功能。当使用Vagrant管理VirtualBox是运行在命令行下面的,而不需要打开界面。

首先,安装VirtualBox,地址

然后,安装Vagrant,地址。安装完成后,将Vagrant的bin目录添加到系统的环境变量Path里面。

再然后,下载做好的虚拟机镜像,地址。我这里下载的是Ubuntu precise 64 VirtualBox,对应链接:http://files.vagrantup.com/precise64.box。这个镜像的下载速度还不错,centos的就不怎么样了,但还是建议先下载到本地硬盘在加载进来。

这时候应该先为这个虚拟机(Ubuntu precise 64)建一个目录,以便初始化和管理这个虚拟机主机。如果有多个虚拟机的话,就分别建立不同的目录来初始化。比如:E:\project\vagrant\dev。然后就在这个目录下面初始化这个镜像。

E:\project\vagrant\dev>vagrant box add Ubuntu12.04x64 "file:///f:\box\precise64.box"

注意,file后面应该是三个/而不是两个。add后面跟的是这个虚拟机的名称,也可以用base自动识别。
打开对应目录下面的配置文件Vagrantfile,配置虚拟机的ip和共享目录。

 config.vm.network "private_network", ip: "192.168.33.10"
 config.vm.synced_folder "E:/wamp/www", "/home/vagrant/www" #将前者映射到后者

初始化并启动:

E:\project\vagrant\dev>vagrant init Ubuntu12.04x64
E:\project\vagrant\dev>vagrant up

vagrant up
然后可以通过ssh连接上去管理了,这里使用Cygwin下面的ssh客户端,默认用户和密码都是vagrant。
vagrant ssh

sudo apt-get update #先更新下软件包,要不然有的可能会装不上

注意启动和连接虚拟机都需要切换到该虚拟机所在开发目录。还有一些其他的命令。

vagrant init  # 初始化
vagrant up  # 启动虚拟机
vagrant halt  # 关闭虚拟机
vagrant reload  # 重启虚拟机
vagrant ssh  # SSH 至虚拟机
vagrant status  # 查看虚拟机运行状态
vagrant destroy  # 销毁当前虚拟机
vagrant package  # 导出当前虚拟机

这里有别人推荐的一个小软件win-sshfs,可以将Linux的目录直接mount到Windows系统上作为一个根盘符。注意:这是个32位软件,可能会安装不成功,需要采用兼容模式。
sshfs
然后就可以在我的电脑里面像本地文件一样管理。

参考链接:
使用 Vagrant 打造跨平台开发环境
使用vagrant和win Sshfs支持openstack开发
Vagrant安装配置
Windows 7使用Vagrant构建虚拟开发环境
Vagrant+VirtualBox搭建统一开发环境