BBEdit.appでハードラップを使って箇条書きの整形をしてみる

●ハードラップ(文字数を指定して強制的に改行する)

プレーンテキストで文章を作成している時に、箇条書きのパートを作ることはよくありますが、その時に文字数を決めてリバースインデントを使って2行目以下を折りたたみたいことがあります。
レイアウトソフトで整形するのであれば、原稿は未整形のままであるべきですが、受け取る側もプレーンテキストで見る場合のことです。
プレーンテキストで送信したいメールなどがこのケースでしょう。
BBEdit.appのテキスト整形能力は非常に高いので、組み込みのコマンドで”Hard Wrap…”というものを備えているのですが、日本語を対象にすると指定した文字数で折り返すのではなく、句読点などと一部の記号を折り返しのマークと認識しているようで、意図した文字数以内で折り返してしまいます。
その上で、禁則はほとんど考慮してくれないという症状です。
そこで、やはりスクリプトで対処することにしました。
折り返しの文字数は、任意に指定できます。

property cNum : "38"

tell application "BBEdit"
	activate
	if (selection of text window 1 as string) is not "" then
		display dialog "折り返しの文字数を指定してください。" default answer cNum buttons {"キャンセル", "設定"} default button 2 with title "折り返しの文字数設定" with icon note returning {text returned:theVart, button returned:theVarb}
		set cNum to theVart
		replace "([^\\n]{" & cNum & "})(?=[^\\n$]*)" using "\\1\\n" searching in the selection of text 1 of text document 1 options {search mode:grep, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
	else
		display notification "文字列を選択してから実行しましょう。" with title "Notification" subtitle ""
	end if
end tell

ダイアログ内の初期値は、設定値に置き換わる(前回の設定値を保持する)仕様なので、毎回リセットしたい場合はダイアログから返される値を代入する変数の名前を変えてください。

●ハードラップをリセットする

ハードラップで強制的に整形した段落を元に戻すスクリプトです。
行頭のインデントも削除するようになっていますので、これを1回実行するだけでリセットできるでしょう。

tell application "BBEdit"
	activate
	if (selection of text window 1 as string) is not "" then
		replace "([^。.)」】])([\\r\\n]+)+([> \\s]*)" using "\\1" searching in selection of text window 1 options {search mode:grep, starting at top:false, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
	else
		display notification "文字列を選択してから実行しましょう。" with title "Notification" subtitle "" --sound name "Frog"
	end if
end tell
広告

BBEdit.appで、行頭に段落番号を追加する/削除するスクリプト

以前、TextWrangler.app用に「Add Line Number.scpt」という名称で、段落番号を追加するスクリプトを公開しましたが、番号が1から開始するだけの仕様だったため、任意の番号から始められるように加筆したものを今回記載します。

●段落番号を追加するスクリプト

選択した範囲の段落の先頭に番号を指定した任意の番号(半角)から順に付加していきます。
オプションとして、桁合わせのために先頭に半角スペースか0を付加することができます。
次に、段落番号の後ろに、区切り文字を入れることができます。デフォルトでは「. 」となっていますが、任意の文字列を指定できます。
(残念ながら、増加分の指定は出来ません)

property Leading : "0"
property SuffixStr : ". "
property ParaList : {}
property LNUm : "1"

on run
	tell application "BBEdit"
		activate
		if (selection of text window 1 as string) is not "" then
			copy every line of selection of text window 1 to ParaList
			set NumParagraphs to count of items in ParaList
			display dialog "段落番号の開始番号を設定してください。" & return & return & "また、桁合わせのリーディングを使用しますか?" buttons {"キャンセル", "使用する", "数字だけ"} default answer LNUm default button 3 with icon note returning {button returned:theVarb, text returned:theVart}
			set LNUm to theVart
			if theVarb is "数字だけ" then
				set Leading to ""
			else
				display dialog "桁合わせのリーディングにゼロ ‘0’を使用しますか?" & return & return & "スペースにしますか?" buttons {"キャンセル", "0", "スペース"} default button 2 with icon note returning {button returned:theVarb}
				if theVarb is "0" then
					set Leading to "0"
				else
					set Leading to " "
				end if
			end if
			display dialog "区切りに ‘.’を使いますか?" & return & return & "スペースにしますか?" default answer SuffixStr buttons {"キャンセル", "設定"} default button 2 with icon note returning {button returned:theVarb2, text returned:theVart2}
			if theVarb2 is "設定" and theVart2 is not "" then
				set SuffixStr to theVart2
			end if
			set theResult to {}
			repeat with i from 1 to NumParagraphs
				if NumParagraphs < 10 then
					set end of theResult to (LNUm - 1 + i) & SuffixStr & item i of ParaList & return
				else if NumParagraphs < 100 then
					set end of theResult to my zeroL2((LNUm - 1 + i), Leading) & SuffixStr & item i of ParaList & return
				else if NumParagraphs < 1000 then
					set end of theResult to my zeroL3((LNUm - 1 + i), Leading) & SuffixStr & item i of ParaList & return
				end if
			end repeat
			set selection of text window 1 to (theResult as string)
		else
			beep
			display notification "文字列を選択してから実行しましょう。" with title "Notification" subtitle "" --sound name "Frog"
		end if
	end tell
end run

to zeroL2(n, leadingChar)
	if n < 10 then
		return leadingChar & n as string
	else if n < 100 then
		return n as string
	else
		return n as string
	end if
end zeroL2

to zeroL3(n, leadingChar)
	if n < 10 then
		return leadingChar & leadingChar & n as string
	else if n < 100 then
		return leadingChar & n as string
	else
		return n as string
	end if
end zeroL3

●行頭の段落番号除去スクリプト

行頭の段落番号除去バージョンです。

tell application "BBEdit"
	activate
	if (selection of text window 1 as string) is not "" then
		replace "^[\\s\\d0-9]+[\\..\\s ]*" using "" searching in selection of text window 1 options {search mode:grep, starting at top:false, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false}
	else
		display notification "文字列を選択してから実行しましょう。" with title "Notification" subtitle ""
	end if
end tell

こちらは区切り文字に合わせて変更しながら使用して下さい。

BBEdit.appのスクリプトパレット

BBEdit.appを使っていると、いつの間にかスクリプトの数が増えて、常用するスクリプトだけをリストアップしているのですが、図のようになっています。

 

図は、スクリプトパレットと呼ばれるようで、「Window」メニューの「Palettes」から「Scripts」を選択することで開けます。
BBEdit.appでは、下の図のようにpreferenceから殆どのメニュー項目にショートカットを設定できますので(ver.11、12で確認)、ここからスクリプトパレットにショートカットを設定しても良いのですが、上の図のようにスクリプトパレットを呼び出す/閉じるスクリプトを書いて、スクリプトパレットに表示させショートカットを割り当てることにしました。

●スクリプトパレットを呼び出す

tell application "BBEdit" to open scripts list

●スクリプトパレットを閉じる

tell application "BBEdit" to close scripts list -- saving no

“open”/”close”だけというシンプルなものです。
ショートカットの設定は、スクリプトパレット上の「Set Shortcut」ボタンをクリックしてから設定するといいでしょう。

BBEdit.appで、「, . .,→。、+全角()[]」の変換スクリプトなど

随分と久し振りに理工学書系統の組版をやりました。以前はほぼ理工学書専門と言っていい時期もあったのですが最近はご無沙汰で、何屋だか分からないような事をやっているのですが…。
そこで、原稿は当然のようにWordということになり、これはもうそれ以外ないようなもので(とは言えTeXで貰ってもねぇ…)Word形式は問題ないのですが、著者ごとに句読点が滅茶苦茶で、半角全角カンマピリオド読点句点のごちゃ混ぜで、かな漢字の間でも半角カンマだったり、今時これはないんじゃないのと頭を抱えたくなる混沌状態でした。
遠い昔、ワープロ全盛期からパソコンへの移行期、プロポーショナルフォントに慣れない世代にこういったことがあったといったことを聞いたことがあります(なんだかこじつけのような気がします…)。
今時こんなでいいのかと思った次第ですが、受けた側としてはなんとかするしかないわけで、結句、今回紹介するようなスクリプトを書く羽目になりました。
これまでも、句読点やパーレンの統一のための変換スクリプトはいくつか書いてはいましたが、今回のようなケースではなんとか手間を省きたいので、半角英数字混じりの文を一括で処理したいと思ったわけです。
原稿によって条件があまりに乱れているので、今回も全てに適用できたわけではないのですが、まあ、一つの足掻きの例として紹介する次第です。

●「, . .,→。、+全角()[]」の変換

変換用のスクリプトは、BBEdit.app用です。

tell application "BBEdit"
	activate
	if (selection of text window 1 as string) is not "" then
		replace "," using "、" searching in the selection of text 1 of text document 1 options {search mode:literal}
		replace "." using "。" searching in the selection of text 1 of text document 1 options {search mode:literal}
		replace "、 *" using "、" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(, *)(?=[^\\x00-\\x7f]+)" using "、" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(\\. *)(?=[^\\x00-\\x7f]+)" using "。" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])(, *)" using "、" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])(\\. *)" using "。" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])( *\\( *)" using "(" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "( *\\( *)(?=[^\\x00-\\x7f]+)" using "(" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "( *\\) *)(?=[^\\x00-\\x7f]+)" using ")" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])( *\\) *)" using ")" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])( *\\[ *)" using "[" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "( *\\[ *)(?=[^\\x00-\\x7f]+)" using "[" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "( *\\] *)(?=[^\\x00-\\x7f]+)" using "]" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])( *\\] *)" using "]" searching in the selection of text 1 of text document 1 options {search mode:grep}
		
		replace "([\\x00-\\x7f]+?)(、)([\\x00-\\x7f]+?)" using "\\1, \\3" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "([\\x00-\\x7f]+?)(.)([\\x00-\\x7f]+?)" using "\\1. \\3" searching in the selection of text 1 of text document 1 options {search mode:grep}
	else
		display notification "文字列を選択してから実行しましょう。" with title "Notification" subtitle ""
	end if
end tell

かなりの悪足掻きです。まだまだ最終解というわけには行かず、参考文献のフォーマット部分の日本語文献では使えないでしょう。

●逆方向ceでは「。、→.,+全角()[]」

tell application "BBEdit"
	activate
	if (selection of text window 1 as string) is not "" then
		replace "、 *" using "," searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "、" using "," searching in the selection of text 1 of text document 1 options {search mode:literal}
		replace "。" using "." searching in the selection of text 1 of text document 1 options {search mode:literal}
		replace "(?<=[^\\x00-\\x7f])( *\\( *)" using "(" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "( *\\( *)(?=[^\\x00-\\x7f]+)" using "(" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "( *\\) *)(?=[^\\x00-\\x7f]+)" using ")" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])( *\\) *)" using ")" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])( *\\[ *)" using "[" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "( *\\[ *)(?=[^\\x00-\\x7f]+)" using "[" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "( *\\] *)(?=[^\\x00-\\x7f]+)" using "]" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "(?<=[^\\x00-\\x7f])( *\\] *)" using "]" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "([\\x00-\\x7f]+?)(、)([\\x00-\\x7f]+?)" using "\\1, \\3" searching in the selection of text 1 of text document 1 options {search mode:grep}
		replace "([\\x00-\\x7f]+?)(.)([\\x00-\\x7f]+?)" using "\\1. \\3" searching in the selection of text 1 of text document 1 options {search mode:grep}
	else
		display notification "文字列を選択してから実行しましょう。" with title "Notification" subtitle ""
	end if
end tell

こちらも同じように限定された条件では破綻します。
まあ、万能な対応というものは出来ないのでしょうが、なんだか不完全燃焼気味ではありますし、まだまだ何度も書き直しをやることになる気がします。

●行頭行末スペース除去

tell application "BBEdit"
	activate
	if (selection of text window 1 as string) is not "" then
		display dialog "行頭・行末のタブ削除を含みますか?" buttons {"キャンセル", "スペースだけ削除", "タブも含んで削除"} default button 3 with icon note returning {button returned:theVarb}
		if theVarb = "スペースだけ削除" then
			replace "[  ]+$" using "" searching in selection of text window 1 options {search mode:grep}
			replace "^[  ]+" using "" searching in selection of text window 1 options {search mode:grep}
		else if theVarb = "タブも含んで削除" then
			replace "[ \\s]+$" using "" searching in selection of text window 1 options {search mode:grep}
			replace "^[ \\s]+" using "" searching in selection of text window 1 options {search mode:grep}
		end if
	else
		display notification "文字列を選択してから実行しましょう。" with title "Notification" subtitle ""
	end if
end tell

エクセルからのコピーペースト文を対象とした場合に、行頭・行末のタブが邪魔な時には便利です。

●追補-ver.12.1.4で、日本語入力(Japanese InputMethod)が誤動作します

図のように日本語入力(Japanese InputMethod)で変換候補を次々にスクロールしていくと、その変換候補が挿入ポイントのカーソルの右に次々と表示され、それが消えてくれません。
ver.12.1.3まではこんな変な症状は出ませんでしたから、ver.12.1.4固有の問題だと思いたいところです(次のバージョンでは修正されていることを願うばかりです…)。
私は、ダウンロードしておいたver.12.0.2に戻して問題を回避しましたが、旧バージョンをダウンロードしていなくて、オートアップデートで最新版に対応している方は、ver.11をBarebone.comのサイトからダウンロードしてダウングレードするしかないかも知れません。
日本語入力がメインの作業の時は、ソフトラップ時の日本語の折り返し表示に難があるので、CotEditor.appなどを主に使っているので、ver.12.1.4で日本語入力(Japanese InputMethod)が誤動作することに気がつくのが遅れました。
ダウングレードを試している際に、ver.12.1.2ではソフトラップ時の折り返しがウィンドウ幅を超えるという現象にも遭遇しました。日本語環境でBBEdit.appを使い続けるという点で、なかなかハンディが大きいなという思いが湧いてきますが、Grepを使った検索/置換機能の強力さ・式表現の素直さを考えるとそう簡単に手放せないのも現実です。

AppleScriptでプログレスバー – 2

AppleScriptでプログレスバーを表示することについては、ドタバタした内容ながら、ここで紹介しました。
で、デモバージョンとして、”sudo purge”を実行するだけのアプリケーションを書きました。
そう、なんで今更”sudo purge”なんだと思うのですが、適当に処理時間がかかって、プログレスバーを表示するには都合が良かっただけです。

「メモリ開放」に関しては 、Mavericks以降は不要だと言われながらそれなりの数のツールが出ていますが、結局”sudo purge”以上の効果のあるツールを私は知りません。
Appleの、最近のメモリに関する“富豪主義(?)”については、何を言っても無駄な気がしますし、その傾向は留まらないのでしょう。あればありったけ使うので、余裕があればその分だけ積めということのようですから…。

さて、スクリプトは以下のようになります。

property UserName : ""
property UserPasswd : ""
property y : ""
property DialogPath : "/Applications/Dialog.app"

on run
	set y to path to me
	my checkPass_Name()
	my do_do()
	delay 1
	my done_done()
end run

on checkPass_Name()
	tell application "Finder"
		set UserPasswd to comment of (y as alias)
	end tell
	tell application "System Events" to set UserName to name of current user
	if UserName is "" then
		activate
		display dialog "ログインユーザ名を入力してください。" buttons {"キャンセル", "設定"} default answer "" default button 2 with icon caution returning {text returned:theVart, button returned:theVarb}
		if theVart is not "" then
			set UserName to theVart
		else
			return
		end if
	end if
	if UserPasswd is "" then
		activate
		display dialog "ログインパスワードを入力してください。" buttons {"キャンセル", "設定"} default answer "" default button 2 with icon caution with hidden answer returning {text returned:theVart, button returned:theVarb}
		if theVart is not "" then
			set UserPasswd to theVart
			tell application "Finder" to set comment of (y as alias) to UserPasswd
		else
			return
		end if
	end if
end checkPass_Name

on do_do()
	activate
	display dialog "キャッシュファイルの解放を行います。" buttons {"Cancel", "Do Purge!"} default button 2 with icon 1 giving up after 3
	try
		do shell script "open " & quoted form of DialogPath
		delay 1
		do shell script "sudo /usr/sbin/purge" user name UserName password UserPasswd with administrator privileges
	end try
end do_do

to done_done()
	beep 3
	display notification "ディスクキャッシュを解放しました。" with title "完了"
	delay 0.1
	do shell script "killall applet"
end done_done

ダイアログでプログレスバーを表示するアプリケーションはここで紹介した‘Dialog.app’を「アプリケーションフォルダ」へ入れて使う場合のスクリプトです。
‘Dialog.app’の名称を‘ProgressBar.app’とでもしておけばよかったと後で思ったのですが、まあいいでしょう。

デモアプリケーション

上記のアップルスクリプトとほぼ同じ内容のアプリケーションを”デモ版”として用意しました。ダイアログでプログレスバーを表示するアプリケーション‘Dialog.app’は別途に用意しなくても動作するようにバインドしています(編集可能な形式で保存していますので、パッケージの中身を見ていただければバインドのやり方がわかるでしょう)。

下記アドレスからダウンロード可能としました。
http://amstudio.sytes.net/amweb/purge_mem_prgrs.iso.zip

※アプリケーションの著作権は放棄いたしませんが、対価は不要です。自己責任で、自由にお使いください。
インターネット上のリンクは、作者への事前/事後の承諾は不要ですので、自由にリンクして下さい。
基本的に、再配布・転載は認めません。

保証

動作に関する保証はいたしません。また、使用によって生じたと思われるいかなる損害に対しても、作者は一切責任を負いません。使用は御自身の責任において行なってください。

Gooey Gadgets.appなき今 – AppleScriptでプログレスバーもどきを作ってみる

macOS Sierraとなってから(だった思います)‘Gooey Gadgets.app’が起動できなくなってしまったので、AppleScriptからプログレスバーを簡単に表示できる手段を失ってしまった格好です。

‘Gooey Gadgets.app’を使っていた際の手順は以下のような行程でした。

  • Script内でメインの処理プロセスをコールする直前に外部プロセスとしてプログレスバーを呼び出す
  • Script内の処理が終わった段階でプログレスバー表示を終了させる
  • 後処理としてScriptの終了処理をする

調べてみると‘cocoaDialog.app’というアプリケーションがあるようです(ザリガニが見ていた…さんのページを参考にしました)。
が、使ってみると、スクリプト内から‘do shell script…’で“ –indeterminate”モードでコールすると、Script内のプロセスとして‘cocoaDialog’が組み込まれてしまうので、Scriptの次のステップに移れなくなってしまい、私の技量レベルでは使えそうにありません。
(別プロセスとして‘cocoaDialog.app’を起動するためのアプリケーションを用意するという手がありそうですが、あまり気乗りのする手段ではなさそうです。)

こうなれば自作してみる – AppleScript

私が欲しいものは、進捗状況を反映したものではなく、単に“処理中です…”などのテキストを表示してくれればいいだけのものです。まさに‘Gooey Gadgets.app’のようなシンプルなアプリケーションであればいいのです。
プログレスバーに進捗状況を反映させるだけの技量はないので、プログレスバーもどきとしてScriptの処理中に画面に“処理中…”などと表示させればいいので、AppleScriptの‘progress’を使ってアプリケーションを仕立ててみることにしました。
Script自体はいたって簡単です。

set progress total steps to 100 -- ここから
repeat with i from 1 to 100
	set progress completed steps to i
	delay 0.2
end repeat -- ここまでは、まさにダミーで、なんら進捗状況を反映しているわけではありません。
set progress description to "処理中です。
しばらくお待ちください..."
with timeout of 7200 seconds -- まあ2時間もあればいいかと...
	set progress total steps to -1
	delay 7200
end timeout

必ず、アプリケーション形式で保存します。今回は、そのまま‘Dialog.app’という名前で、アプリケーションフォルダ内へ保存しました。
固定表示の時間設定は、使い勝手に合わせて適当に書き換えればいいでしょうが、中途半端に短いとScriptの処理の途中で画面表示が終わってしまいます。

Script内で呼び出す時は、

‘do shell script “/Applications/Dialog.app/Contents/MacOS/applet”’

あるいは

‘do shell script “open /Applications/Dialog.app”’

で呼び出せばいいでしょう(アプリケーションフォルダ内を前提にしています)。(直接実行ファイルを叩くと、外部アプリケーションとして扱えないようで、appletの処理待ちになってしまいますので、‘do shell script “open /Applications/Dialog.app”’という起動の仕方を使ってください — 2017.06.23)
‘Dialog.app’を終了させてダイアログを消す時は、‘do shell script “killall applet”’を使った方が間違いがないようです。‘tell application “Dialog” to quit’でやると、何度か空振りしてしまいました。
‘do shell script “killall applet”’を使う時には、同時に複数のAppleScriptアプリケーションが起動していないように注意してください。

と、ここまで書いた後に、実行ファイル、”/Applications/Dialog.app/Contents/MacOS/applet”の名称を‘applet’から‘Dialog’にリネームしてみました。動きました。
となると、
Script内で呼び出す時は、

‘do shell script “/Applications/Dialog.app/Contents/MacOS/Dialog”’

でOKで、終了は、

‘do shell script “killall Dialog”’

でいけることになります。

補足と修正 – 17.06.21

実行ファイル、”/Applications/Dialog.app/Contents/MacOS/applet”の名称を‘applet’から‘Dialog’にリネーム後に、‘Info.plist’の中も書き換えていたことを書き忘れていたのですが、その後、再現してみると‘Info.plist’を書き換えると、アプリケーションの起動時に初期画面が出てしまうことがわかりました。現時点で、リネームしてそのまま起動させる方法が分からなくなってしまったのでリネームなしで使った方がいいようです。m(._.)m

ダウンロード

アプリケーションを下記アドレスからダウンロード可能としました。
http://amstudio.sytes.net/amweb/Dialog.iso.zip

(このアプリケーションは、”Dialog.app/Contents/MacOS/applet”の名前を変更していません。環境に合わせて、必要であればリネームしてください)

※アプリケーションの著作権は放棄いたしませんが、対価は不要です。自己責任で、自由にお使いください。
インターネット上のリンクは、作者への事前/事後の承諾は不要ですので、自由にリンクして下さい。
基本的に、再配布・転載は認めません。

保証

動作に関する保証はいたしません。また、使用によって生じたと思われるいかなる損害に対しても、作者は一切責任を負いません。使用は御自身の責任において行なってください。