Selected Safari Tabs to Markdown Reference Links

最近看到好几个讨论 Markdown 引用式链接(Reference link)的文章和解决方案,于是 Lucifr 我又是各种折腾,便有了现在这个 Workflow:Tabs to Refs。本来是想通过 TextExpander 来实现,后来发现这货对 Applescript 的对话框调用还是很不给力,于是还是通过 Automator 做成了一个 Service,可以在各种文本编辑器中使用(当然是 Mac only)。

用途

在 Markdown 中有这两种链接的方式,一种是 inline 型的,也就是在内文里直接加上链接:

[Lucifr](http://lucifr.com) 是个怪蜀黍。

另一种就是引用型的:

[Lucifr][1]是个怪蜀黍。

[1]: http://lucifr.com

两种的最终输出效果没什么不同,但是在写作过程中就不太一样,前者适合一篇文章中链接较少且基本上不重复使用链接的情况,而后者在大量使用链接且重复使用多的情况下就比较方便了。

此外引用型还有一个好处,就是可以一次性将要用到的链接都先列到文章中,再进行写作。但输入引用型链接却是个苦差事,Tabs to Refs 就是帮助 Lucifr 让这一输入过程变得更简单些。

首先我会通过各种途径来收集资料,最终这些来源都集中在 Safari 当中,但这里面有我需要的链接也有一些是不需要的,我不想它们都出现在我的编辑器中然后再去一个个删除。

我需要做的是在文本编辑器中运行这个 Service,而它会将 Safari 最前面的窗口中所有 Tab 的链接和对应的标题收集起来,并弹出一个选择对话框:

Tabs to Refs: Dialog

这是一个多选的对话框,我可以按住 Command 键来选择多个需要的项目。确定后它会将我所选择的 Tab 处理成我需要的序号式引用格式并插入到当前文本的末尾。

因为是序号式的引用链接,因此在这一过程中,它还需要完成另一个任务:在已有的文本中进行匹配,当文本中已存在引用链接时,自动延续之前的序号。

实现

基本上都是用 Applescript 来完成的,我借鉴和借用了不少别人的代码,比如:

最终成为了以下这段丑陋的代码:

tell application "System Events"
	set currentClipboard to the clipboard
	keystroke "a" using {command down}
	keystroke "c" using {command down}
	delay 0.5
	set myText to the clipboard
	keystroke "v" using {command down}
	delay 0.5
	set the clipboard to currentClipboard
end tell
set myRef to do shell script "~/bin/bbstdin  " & quoted form of myText & " | ~/bin/nextreflink"
set front_app to (path to frontmost application as Unicode text)
set url_list to {}
set ref_list to {}
tell application "Safari"
	repeat with t in every tab in front window
		set TabTitle to (name of t)
		set TabURL to (URL of t)
		if length of TabURL > 30 then
			set newTabURL to text 1 thru 20 of TabURL & "..." & text -10 thru end of TabURL
		else
			set newTabURL to TabURL
		end if
		if length of TabTitle > 50 then
			set newTabTitle to (text 1 thru 30 of TabTitle as text) & "..." & text -20 thru end of TabTitle
		else
			set newTabTitle to TabTitle
		end if
		set url_list to url_list & (newTabTitle & " - " & newTabURL)
		set ref_list to ref_list & (TabURL & space & quote & TabTitle & quote & linefeed)
	end repeat
end tell
set ref_output to ""
repeat with l in getchosenItemNums(url_list)
	set ref_output to ref_output & "[" & myRef & "]: " & item l of ref_list
	set myRef to myRef + 1
end repeat
set refsList to return & text 1 thru -2 of ref_output

tell application front_app
	activate
end tell

tell application "System Events"
	set currentClipboard to the clipboard
	set the clipboard to refsList
	keystroke "v" using {command down}
	delay 0.5
	set the clipboard to currentClipboard
end tell

on leadingZeros(n)
	return text -2 thru -1 of (100 + n as text)
end leadingZeros

to getchosenItemNums(aList)
	tell me
		activate
		set numList to {}
		set chosen to {}
		repeat with k from 1 to count aList
			set end of numList to my leadingZeros(k) & ". " & item k of aList
		end repeat
		set choices to choose from list numList with title "Tabs to Refs" with prompt "Hold the Command key down to make multiple choices." with multiple selections allowed
		repeat with j from 1 to count choices
			tell choices to set end of chosen to (text 1 thru ((my (offset of "." in item j)) - 1) of item j) as integer
		end repeat
		return chosen
	end tell
end getchosenItemNums

其中的 bbstdin 和 nextreflink 来自 @drdrangMarkdown reference links in BBEdit

#!/bin/bash
echo -n $1 | perl -015 -l12 -p -e0

#!/usr/bin/python

import sys
import re

text = sys.stdin.read()
reflinks = re.findall(r'^\[(\d+)\]: ', text, re.MULTILINE)
if len(reflinks) == 0:
  print 1
else:
  print max(int(x) for x in reflinks) + 1

使用

  1. 下载 Tabs to Refs.workflow,放到 ~/Library/Services/ 目录当中。

  2. 保存 bbstdin 和 nextreflink 放到 ~/bin/,并通过终端运行以下命令使其可被运行:

    chmod u+x ~/bin/bbstdin && chmod u+x ~/bin/nextreflink
    
  3. 在文本编辑器中通过点击菜单栏中程序名,选择 “Services”(服务) -> “Tabs to Refs”。当然你也可以通过系统设置中的快捷键选项为 Tabs to Refs 指定一个快捷键来方便调用。

    Tabs to Refs: Shortcut

Lucifr

Read more posts by this author.

Beijing, China http://lucifr.com