Pythonista3 のeditor module を使い、Pythonista3 のコーディングを楽にする


この記事は、[Pythonista3 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/pythonista3) の03日目の記事です。


https://qiita.com/advent-calendar/2022/pythonista3

一方的な偏った目線で、Pythonista3 を紹介していきます。

ほぼ毎日iPhone（Pythonista3）で、コーディングをしている者です。よろしくお願いします。

以下、私の2022年12月時点の環境です。


```
--- SYSTEM INFORMATION ---
**System Information**

* Pythonista 3.3 (330025), Default interpreter 3.6.1
* iOS 16.0.2, model iPhone12,1, resolution (portrait) 828.0 x 1792.0 @ 2.0
```

他の環境(iPad や端末の種類、iOS のバージョン違い)では、意図としない挙動(エラーになる)なる場合もあります。ご了承ください。

ちなみに、`model iPhone12,1` は、iPhone11 です。

## はじめに

「携帯でコードを書くのが面倒なら、コードを書いて楽にすればいいじゃない」

天啓を受けました、よろしくお願いします。

今回は、Pythonista3 でのコーディングをPythonista3 を使ってもっと快適にしよう。が、テーマです。

- 編集中のコードテキストを全コピーする
- 編集中のファイルパスを取得する

2点とあとおまけ的なものを紹介できればと思います。

基本的にiPhone でコードを書いているので、iPad でPythonista3 を楽しんでいる方には、不要なものもあるかもしれません。

## `editor` module

[editor — Functions for scripting Pythonista’s text editor — Python 3.6.1 documentation](https://omz-software.com/pythonista/docs/ios/editor.html)

https://omz-software.com/pythonista/docs/ios/editor.html

> Pythonistaのテキストエディタをスクリプト化するための機能

名前ズバりの`editor` を使います。

> editorモジュールは、現在編集中のスクリプトへのアクセスを提供します。選択した範囲の取得や設定、指定した範囲のテキストを置換することができます。
> 注意：選択とテキスト操作の機能に対する無効な入力値（例：範囲外）は、今のところ黙って無視されます。これは、将来のリリースで変更される可能性があります。
> このモジュールは、カスタマイズ可能なアクションメニュー（v1.1の新機能）と組み合わせると特に便利です。ライブラリから任意のスクリプトをメニューに追加し、現在編集中のスクリプトに関係なく、エディタから直接素早く実行することができます。メニューは設定から編集可能です（Editor > Actions Menu）。
> これにより、Pythonistaアプリの機能を拡張する、いくつかの非常に興味深い可能性が生まれます。インスピレーションを得るために、アクションとして使用できるスニペットをいくつか紹介します。

機械翻訳をそのまま貼り付けました！

### Editor Action

[App Extensions and Shortcuts — Python 3.6.1 documentation](https://omz-software.com/pythonista/docs/ios/pythonista_shortcuts.html#editor-action)

https://omz-software.com/pythonista/docs/ios/pythonista_shortcuts.html#editor-action


便利にするコードを事前に用意しておいて、他ファイルを編集中に便利コードを実行したいので、Editor Action 機能を使います。


![img221115_002407.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/3cb3afbe-444c-9510-0fe2-e853ddfb1cd4.gif)



右上のレンチアイコンをタップすると、Editor Action を呼び出せる画面が出てきます。

![img221115_003441.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/12ffc5da-10c1-c07c-d71d-4f84112ed76b.png)


コードをEditor Action に指定したいので、`Edit` をタップし編集モードにします。


![img221115_003603.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/e0a0fd77-60ae-88f2-5a37-15c2eeaaeec3.png)


![img221115_003613.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/e1c5be6f-3627-9774-1cf6-862cac7c2f96.png)


Editor Action にしたいコードの場合は、`Run Script` は、そのままで大丈夫です。

もし、他のコードを使いたいのであれば、ファイル名をタップし、該当ファイルまで移動させます（`External Files` の外部のファイルは選択できません）。

アイコンの変更や、色の設定もできるので、視認しやすいものを選んでみてください。


![img221115_003937.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/1f838224-256d-0b29-00c1-b39dce8fd761.png)



最後に、`Add` をタップし、`Done` をタップすれば、Editor Action 設定完了です。

設定方法がわかったので、コードを実際に書いていきましょう。

## 編集中のコードテキストを全コピーする

iPhone で、気軽に`[cmd or ctrl] + [a] -> [cmd or ctrl] + [v]` がやりたいのです。

ミニマムの完成コードは、以下で完了です。

```py
import editor
import clipboard

txt = editor.get_text()
clipboard.set(txt)

```

このコードをEditor Action で実行すると、開いているファイルの内容を、クリップボードに保存してくれます。

Editor Action 実行後に、ペーストをするとコピーしたコードを貼り付けることができます。

クリップボードに保存されているので、Pythonista3 以外のメモでもSafari でもTwitter にでも、ペーストが可能です。

### 解説

たった4行に、解説もクソもないですが、挙動について確認できればと思います。

```py
import editor

txt = editor.get_text()
print(txt)

```


![img221115_010058.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/a7563d1e-bf06-53e6-20e3-34feee74bfe4.gif)


`editor.get_text()` で、現在開いるファイルのテキストを取得します。

文字列`Str` で返ってきます。

今回は、自身のファイル上で実行をしたので、コンソールに自身のコードが出力されました。

[clipboard — Copy and paste — Python 3.6.1 documentation](https://omz-software.com/pythonista/docs/ios/clipboard.html) は、`set` でclipboardに登録。`get` でclipboardの中身を取得できます。

https://omz-software.com/pythonista/docs/ios/clipboard.html


```py
import clipboard

cb = clipboard.get()
print(cb)

```

試しに、現在のclipboard に何が入っているか確認してみましょう。それぞれ、事前何をコピーしたかによって結果が変わってきます。


- テキストを選択しコピー

![img221115_085125.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/a95775b4-881c-c5c8-f0be-be1292119b09.png)


- コードを実行

![img221115_085135.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/7e649050-6b2d-1a32-4365-9f54f874b33f.png)


- console に結果が出る

![img221115_085144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/e4bcf3ea-99b4-6496-2972-e28a4649ccec.png)



思ったより簡単ですかね？

Python の書き方は、解説予定はないのですが、雰囲気的に、「取ってきて、入れる」みたいなイメージで実装できると思います。

次は、ファイルパスの取得です。

## 編集中のファイルパスを取得する

他のコードへ編集中のパスを指定したい場合（ファイルや、画像）、入力するよりも、正確性を担保したいですよね。

Pythonista3 には、ファイルパスの補完機能がないので、typo したエラーを見つけるのも面倒だったりします。

また、他のアプリとの連携の際にも長いパスを入力することもなくなります。

またもや、数行で完結します。

```py

import editor
import clipboard

path = editor.get_path()
clipboard.set(str(path))

```

### 解説

`.get_text()` が`.get_path()` に変わっただけです。

いい感じに、Pythonista3 が関数を用意してくれていますね！

クリップボードに格納されている文字列は、ファイルがある場所になっています（実行場所により、後半部分が違います）。

`/private/var/mobile/Containers/Shared/AppGroup/~省略~/Pythonista3/Documents/sample.py`

## フィードバックをひとつまみ🤏

（iPhone のみ実装可能です🙇）

達成したい機能としては、無事に実装ができました。ﾔｯﾀﾈ!

ここはひとつのブラッシュアップとして「処理が完了したフィードバック」を追加してみたいと思います。

### 機能と感覚

今回2つのスクリプトは、クリップボードに値を格納する形式のため、結果の判断が瞬時には難しい状態です。

`「完了しました！」`popup でもいいかもしれませんが、処理をする内容と比較すると、重たすぎる（鬱陶しい）印象です。

もう少し軽量な通知方法として、iPhone のバイブレーション機能を借りてみることにしましょう。

処理完了が「ブルッ」と震えてくれれば、「お！完了やな！」と瞬時に感じ取れるでしょう。

便利な機能と、わかりやすい反応。最高ですね☺️

### 「無い」のであれば「作る（呼ぶ）」

しかし誠に残念ながら、バイブレーションを呼び出す関数は、Pythonista3 で用意されていません。。。

せっかく「通知をバイブレーションにすることで、いい感じになりそう！」と、考えたのに。悲しい話です😭

大丈夫です。諦めることはありません！

Pythonista3 で機能が無いのであれば、こっちで作って呼び出せばいいのです！！

#### 召喚の儀

[objc_util — Utilities for bridging Objective-C APIs — Python 3.6.1 documentation](https://omz-software.com/pythonista/docs/ios/objc_util.html)

https://omz-software.com/pythonista/docs/ios/objc_util.html

Pythonista3 で用意されている`objc_util` というモジュールを使います。

このモジュールは、なかなかのなかなかなモジュールですので、説明する記事を別途準備しております。

今回はコピペで。「なんか呪文唱えてるよコイツ、、、」と思っていてください。

#### UIImpactFeedbackGenerator

Haptic Feedback（触覚フィードバック）という、「ブルッ」「コリっ」とした反応を返すiOS の機能（API）を使います。

[UIFeedbackGeneratorの使い方と便利に使えるライブラリ - Qiita](https://qiita.com/WorldDownTown/items/2b5a72e41a95763727bb)

https://qiita.com/WorldDownTown/items/2b5a72e41a95763727bb

[UIImpactFeedbackGenerator | Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uiimpactfeedbackgenerator?language=objc)

https://developer.apple.com/documentation/uikit/uiimpactfeedbackgenerator?language=objc


Pythonista3 で使うには、こんなコードにします。

```py
from objc_util import ObjCClass


def get_feedback_generator(style=4):
  """
  todo: style 0-4
  call feedback ex:
  `UIImpactFeedbackGenerator.impactOccurred()`
  """
  UIImpactFeedbackGenerator = ObjCClass('UIImpactFeedbackGenerator').new()
  UIImpactFeedbackGenerator.prepare()
  UIImpactFeedbackGenerator.initWithStyle_(style)
  return UIImpactFeedbackGenerator


feedback = get_feedback_generator(4)
feedback.impactOccurred()

```

（コード内のコメントの書き方は許してください🙇）

`get_feedback_generator(4)` の`4` の整数部分は、`0〜4` で強さが変化します。

ちなみに、他の整数値を入れると、Pythonista3 が落ちます（歓喜）。

ぜひ、実行して感覚の変化を楽しんでみてください。

## 最終形態

「機能面」も「使用面」も整ったので、悪魔合体をしていきましょう。

（イキって、`if __name__ == '__main__':` や`main` 関数使ってます）

Editor Action 登録にあたり、ファイル名は

- 編集中のコードテキストを全コピーする
  - `get_text.py`
- 編集中のファイルパスを取得する
  - `get_path.py`

アイコンは、以下のようなものを使ってます。


![img221116_131816.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/95290ef3-9d7b-4e3a-b0fd-3d5ba68b465a.png)



Editor Action 登録のGIF 再掲します。

![img221115_002407.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/3cb3afbe-444c-9510-0fe2-e853ddfb1cd4.gif)


#### `get_text` 全貌

```get_text.py
import editor
import clipboard
from objc_util import ObjCClass


def get_feedback_generator(style=4):
  """
  todo: style 0-4
  call feedback ex:
  `UIImpactFeedbackGenerator.impactOccurred()`
  """
  UIImpactFeedbackGenerator = ObjCClass('UIImpactFeedbackGenerator').new()
  UIImpactFeedbackGenerator.prepare()
  UIImpactFeedbackGenerator.initWithStyle_(style)
  return UIImpactFeedbackGenerator


def main():
  feedback = get_feedback_generator(4)
  txt = editor.get_text()
  clipboard.set(txt)
  feedback.impactOccurred()


if __name__ == '__main__':
  main()

```

#### `get_path` 全貌

```get_path.py
import editor
import clipboard
from objc_util import ObjCClass


def get_feedback_generator(style=4):
  """
  todo: style 0-4
  call feedback ex:
  `UIImpactFeedbackGenerator.impactOccurred()`
  """
  UIImpactFeedbackGenerator = ObjCClass('UIImpactFeedbackGenerator').new()
  UIImpactFeedbackGenerator.prepare()
  UIImpactFeedbackGenerator.initWithStyle_(style)
  return UIImpactFeedbackGenerator


def main():
  feedback = get_feedback_generator(4)
  path = editor.get_path()
  clipboard.set(str(path))
  feedback.impactOccurred()


if __name__ == '__main__':
  main()

```

## おまけ

今までまでのコードの汎用で、他色々なものを組み合わせて作ったスクリプトをおまけとして紹介します。

### Pythonista3 内だけで、英語を日本語に機械翻訳

iOS16 になってから、アプリ間でのペーストに一手間承認を求めるプロセスが増えました。


![img221116_134722.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/b14a71ef-3116-c997-4131-f2c8cf7fe7e7.png)



「許可」を押すのが面倒 & Pythonista3 アプリ内に居続けたい強い思いから、Editor Action を使いPythonista3 内で完結する翻訳機能を実装してみました。


![img221116_154839.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953777/7696298b-02dc-a51c-7fb0-99a416ebe3e6.gif)



翻訳したいテキスト（英語）を選択、Editor Action を実行すると、クリップボードに翻訳結果（日本語）が格納されます。

ペーストすることで、翻訳結果が挿入される戦法です。

#### 過去のフロー

1. 翻訳したいテキストをコピー
1. 翻訳アプリへペースト
1. 翻訳内容をコピー
1. どこかにペースト

アプリ間を行ったり来たりの繰り返しです。

そして、毎回ペースト時に「許可」をタップすることになります。

#### Google翻訳API を使う

この記事内容をまるっと行いました。

[Google翻訳APIを無料で作る方法 - Qiita](https://qiita.com/satto_sann/items/be4177360a0bc3691fdf)

https://qiita.com/satto_sann/items/be4177360a0bc3691fdf


GAS（Google Apps Script）を雰囲気（だいじ）で使っていたのでなんとかなりました。

#### `requests` モジュール

ネットワークへリクエストする。みたいなことを普段は行わないので、`requests` モジュールについて何も言えないのですが、Pythonista3 にデフォルトで入っています。

レスポンス結果がJSON 形式で返ってくるので、いい感じに処理をします。

[クイックスタート — requests-docs-ja 1.0.4 documentation](https://requests-docs-ja.readthedocs.io/en/latest/user/quickstart/#json)

https://requests-docs-ja.readthedocs.io/en/latest/user/quickstart/#json


#### コードの全貌

`URL` の部分は、自分で作成したウェブアプリケーションのURL に置き換えてください。

```googleTranslation.py
# [Google翻訳APIを無料で作る方法 - Qiita](https://qiita.com/satto_sann/items/be4177360a0bc3691fdf)

import requests

from objc_util import ObjCClass
import editor
import clipboard

URL = '自分で作ったウェブアプリケーションのURL'


def get_params(text):
  _params = {'text': f'{text}', 'source': 'en', 'target': 'ja'}
  return _params


def get_feedback_generator(style=4):
  """
  todo: style 0-4
  call feedback ex:
  `UIImpactFeedbackGenerator.impactOccurred()`
  """
  UIImpactFeedbackGenerator = ObjCClass('UIImpactFeedbackGenerator').new()
  UIImpactFeedbackGenerator.prepare()
  UIImpactFeedbackGenerator.initWithStyle_(style)
  return UIImpactFeedbackGenerator


def main():
  feedback = get_feedback_generator(4)

  all_text = editor.get_text()
  selection_start_end = editor.get_selection()
  [s, e] = selection_start_end if selection_start_end else [0, 0]
  select_text = all_text[s:e]

  if select_text:
    params = get_params(select_text)
    r = requests.get(URL, params=params)
    text_json = r.json()
    out_text = text_json['text']

    clipboard.set(f'{out_text}')

  feedback.impactOccurred()


if __name__ == '__main__':
  main()

```

リクエストからレスポンスまで時間が読めないので、フィードバックの恩恵を強く感じることができるでしょう。

## 次回は

Editor Action 機能と`editor` モジュールを中心に、Pythonista3 を使ってPythonista3 を便利に楽に使う方法を紹介しました。

ふと「面倒だなぁ」と感じる場面に遭遇した際、「Pythonista3 で解決できるのでは？🤔」と、考えてみると面白いかもしれません。

次回も、Pythonista3 を便利に使うスクリプトを紹介します。私が日常的に使っている頻度No.1 を争うであろう2つのスクリプトで、キーボード周りを触っていきます。

他にもDocumentation から使えそうなものを探して試してみるのもいいでしょう！


ここまで、読んでいただきありがとうございました。

## せんでん

### Discord

Pythonista3 の日本語コミュニティーがあります。みなさん優しくて、わからないところも親身に教えてくれるのでこの機会に覗いてみてください。

https://t.co/0IOW2hn1VC

### 書籍

iPhone/iPad でプログラミングする最強の本。

- [Python や Jupyter で iPhone/iPad 先端機能を簡単･自由にプログラミング！「活用篇」：hirax](https://techbookfest.org/product/1WiyV4LEev3f4YrzesRKWV?productVariantID=axX32srsSgtLtZWUtjkj99)

https://techbookfest.org/product/1WiyV4LEev3f4YrzesRKWV?productVariantID=axX32srsSgtLtZWUtjkj99

- [Python や Jupyter で iPhone/iPad 先端機能を簡単･自由にプログラミング！「土台篇」：hirax](https://techbookfest.org/product/wTZTyeibm5GQ5XgdfMrEBV?productVariantID=kRDmN1udbEYZUWbETdwL8r)

https://techbookfest.org/product/wTZTyeibm5GQ5XgdfMrEBV?productVariantID=kRDmN1udbEYZUWbETdwL8r

### その他

- サンプルコード

[Pythonista3 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/pythonista3) でのコードをまとめているリポジトリがあります。

コードのエラーや変なところや改善点など。ご指摘やPR お待ちしておりますー

https://github.com/pome-ta/Pythonista3AdventCalendar2022sampleCode

- Twitter

なんしかガチャガチャしていますが、お気兼ねなくお声がけくださいませー

https://twitter.com/pome_ta93

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">やれるか、やれないか。ではなく、やるんだけども、紹介説明することは尽きないと思うけど、締め切り守れるか？って話よ！（クズ）<br><br>Pythonista3 Advent Calendar 2022 <a href="https://t.co/JKUxA525Pt">https://t.co/JKUxA525Pt</a> <a href="https://twitter.com/hashtag/Qiita?src=hash&amp;ref_src=twsrc%5Etfw">#Qiita</a></p>&mdash; pome-ta (@pome_ta93) <a href="https://twitter.com/pome_ta93/status/1588570697777152006?ref_src=twsrc%5Etfw">November 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

- GitHub

基本的にGitHub にコードをあげているので、何にハマって何を実装しているのか観測できると思います。

https://github.com/pome-ta