テキストを「1行ごとのリスト」ととらえ、削除と移動を可能に〜1Writerカスタマイズ①〜

タスク管理アプリの多くは、長年使っている「たすくま」もそうですが「リスト」の形式をとっています。

1タスク1リスト(1タスク1行)の表示で、タスクがダァーッと並んでいる形式。
確かにこの形式は、タスク管理をする上で扱いやすいなぁと感じます。
リスト形式であれば、

  • 行の削除ができる
  • 行の順番の入れ替えができる

という機能を備えており、それがタスクを扱いやすくしてくれている要因ではないか、ということで、「やったことの記録がすこぶる取りやすいリストアプリ」のように、テキストを扱えるようにしたいな、という思いがわいたわけでした。
「アウトライナー」をタスク管理に利用している方も多くいられると思うのですが、それは、アウトライナーは行の削除と順番の入れ替えが容易であるというのも大いに関係していると感じます。

ぼくは、タスク管理に今はObsidianを使っているのですが、iPhoneでは、「1Writer」というアプリを使っています。

1Writer – Markdown Text Editor
カテゴリ: 仕事効率化, ユーティリティ

1Writerはjavascriptを扱えますので、テキストを加工することができます。そこで、1Writerのjavascript機能を使って、

  • 行の削除ができる
  • 行の順番の入れ替えができる

という機能を実装しようと考えました。
そうして作成したのが、以下の3つのアクション。

  • カーソル(選択)行を削除
  • カーソル(選択)行を上へ移動
  • カーソル(選択)行を下へ移動

カーソル(選択)行を削除

var text = editor.getText();
var linetexts = text.split('\n');
const range = editor.getSelectedRange();
var s = range[0];
var e = range[1];
var selects;
var selecte;
var linecount = 0;
var selectrange;
for (let i = 0; i < linetexts.length; i++){
    if ( s <
        linecount + linetexts[i].length +1){
        selects = i;
        selectrange = linecount - 1;
        break;
    }else{
        linecount += linetexts[i].length + 1;
    }
}
linecount = 0;
for (let i = 0; i < linetexts.length; i++){
    if ( e <
        linecount + linetexts[i].length +1){
        selecte = i;
        break;
    }else{
        linecount += linetexts[i].length + 1;
    }
}

var before = -1;
for(let i=0; i < selects;i++){
    before = before + linetexts[i].length + 1;
}
var after = before;
if(before < 0){
    before = 0;
}
for(let i=selects; i < selecte+1;i++){
    after = after + linetexts[i].length + 1;
}
editor.replaceTextInRange(before, after, "")

カーソル(選択)行を上へ移動

var text = editor.getText();
var linetexts = text.split('\n');
const range = editor.getSelectedRange();
var s = range[0];
var e = range[1];
var selects;
var selecte;
var linecount = 0;
var selectrange;
for (let i = 0; i < linetexts.length; i++){
    if ( s <
        linecount + linetexts[i].length +1){
        selects = i;
        selectrange = linecount - 1;
    break;
    }else{
        linecount += linetexts[i].length + 1;
    }
}
linecount = 0;
for (let i = 0; i < linetexts.length; i++){
    if ( e <
        linecount + linetexts[i].length +1){
        selecte = i;
        break;
    }else{
        linecount += linetexts[i].length + 1;
    }
}

var before = 0;
for(let i=0; i < selects;i++){
    before = before + linetexts[i].length + 1;
}
var after = before;
if(before < 0){
    before = 0;
}
for(let i=selects; i < selecte+1;i++){
    after = after + linetexts[i].length + 1;
}
editor.replaceTextInRange(before, after, "")
var cutlines = [];
for(let i = 0; i < selecte-selects+1; i++){
    cutlines.push(linetexts[selects + i])
}
var cuttext = cutlines.join('\n');

if ( selects == 0 ){
    editor.replaceTextInRange(0, 0, cuttext + '\n');
    editor.setSelectedRange(cuttext.length,cuttext.length);
}else if( selects == 1 ){
    editor.replaceTextInRange(0, 0, cuttext + '\n');
    editor.setSelectedRange(s - linetexts[0].length-1,e-linetexts[0].length-1);
}else{
    var before = 0;
    for(let i=0; i < selects-1;i++){
        before = before + linetexts[i].length + 1;
    }
    editor.replaceTextInRange(before-1, before-1, '\n'+cuttext)
    editor.setSelectedRange(s - linetexts[selects-1].length-1,e-linetexts[selects-1].length-1);
}

カーソル(選択)行を下へ移動

var text = editor.getText();
var linetexts = text.split('\n');
const range = editor.getSelectedRange();
var s = range[0];
var e = range[1];
var selects;
var selecte;
var linecount = 0;
var selectrange;
for (let i = 0; i < linetexts.length; i++){
    if ( s <
        linecount + linetexts[i].length +1){
        selects = i;
        selectrange = linecount - 1;
        break;
    }else{
        linecount += linetexts[i].length + 1;
    }
}
linecount = 0;
for (let i = 0; i < linetexts.length; i++){
    if ( e <
        linecount + linetexts[i].length +1){
        selecte = i;
        break;
    }else{
        linecount += linetexts[i].length + 1;
    }
}

var before = 0;
for(let i=0; i < selects;i++){
    before = before + linetexts[i].length + 1;
}

if ( selecte == linetexts.length-1 ){

}else{

    var after = before;
    if(before < 0){
        before = 0;
    }
    for(let i=selects; i < selecte+1;i++){
        after = after + linetexts[i].length + 1;
    }
    editor.replaceTextInRange(before, after, "")
    var cutlines = [];
    for(let i = 0; i < selecte-selects+1; i++){
        cutlines.push(linetexts[selects + i])
    }
    var cuttext = cutlines.join('\n');
    var before = 0;
    for(let i=0; i < selecte+1;i++){
        before = before + linetexts[i].length + 1;
    }
    editor.replaceTextInRange(before-1+linetexts[selecte+1].length-cuttext.length, before-1+linetexts[selecte+1].length-cuttext.length, '\n'+cuttext);
    editor.setSelectedRange(s + linetexts[selecte+1].length+1,e+linetexts[selecte+1].length+1);
}

おそらくあんまりキレイなコードではないと思うのですが、、、便利なのでよかったら使ってみてください。

で、これらによって、テキストを行ごとに削除したり移動したりが簡単になったわけです。でも、だいぶと便利になったのに、さらに欲が出てきまして。
もっとダイナミックに移動させたいようになってきました。

つづく

See Also