惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
S
Security @ Cisco Blogs
S
Secure Thoughts
Attack and Defense Labs
Attack and Defense Labs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
Recent Commits to openclaw:main
Recent Commits to openclaw:main
H
Hacker News: Front Page
博客园 - 叶小钗
H
Heimdal Security Blog
Microsoft Security Blog
Microsoft Security Blog
Forbes - Security
Forbes - Security
AI
AI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Troy Hunt's Blog
罗磊的独立博客
Application and Cybersecurity Blog
Application and Cybersecurity Blog
爱范儿
爱范儿
GbyAI
GbyAI
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
D
DataBreaches.Net
Recent Announcements
Recent Announcements
Schneier on Security
Schneier on Security
C
Cisco Blogs
美团技术团队
D
Docker
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
月光博客
月光博客
雷峰网
雷峰网
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
H
Hackread – Cybersecurity News, Data Breaches, AI and More
A
Arctic Wolf
B
Blog RSS Feed
Cisco Talos Blog
Cisco Talos Blog
C
Cybersecurity and Infrastructure Security Agency CISA
V
Vulnerabilities – Threatpost
V2EX - 技术
V2EX - 技术
Y
Y Combinator Blog
N
News and Events Feed by Topic
www.infosecurity-magazine.com
www.infosecurity-magazine.com
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
G
GRAHAM CLULEY
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Hacker News
The Hacker News

Miriam Eric Suzanne

Butter bells, fresh from the kiln Butter bells, fresh from the kiln Butter bells, fresh from the kiln I had to look it up I Laser-cut pottery throwing gauge Tech continues to be political Aggregating my distributed self A web component for CodePen embeds? We don Eleventy buckets & cascade layers A slash-why proposal User styles on the web Custom element, two ways New year, same (terrible) Mia CSS @scope Reclaiming my time Cascade Layers Personal Histories Ancient Web Browsers Critical CSS? Not So Fast! CSS tie-dye gradient backgrounds Personal website redesign Request for Comments: Sass Color Spaces A long-term plan for logical properties? Container queries in browsers! I never let things be small A whole cascade of layers This content won No demo [website] reno 2 days of cordwainery Body margin 8px The gray areas of HWB color Miriam, for the archive Complex vs compound selectors The spam has arrived Am I on the IndieWeb yet? My theatrical delusions A Complete Guide to CSS Cascade Layers Container queries explainer & proposal Very Extremely Practical CSS Art An open CSS notebook Custom Property “Stacks" Alcohol affects the frontal cortex Embracing the Universal Web CSS most normalizer-est Introducing Sass Modules F*CSS Not clear to me, an installation Framed | Born to choose this way Last Bullet, live music video A Dark Plain, live music video Guts | Let Rejecting maleness Chosen family (thank you) Mia Speaking of pride More CSS Charts, with Grid & Custom Properties (Mis)gender Stop Being Productive Fun with Viewport Units Gods on the Lam Body & gender fragments Trans Interviews & Photography Getting Started with CSS Grid Just Like That Adaptation: SideSaddle/Myths Justice [under construction] Some clarifications on trans language Some kind of resistance tour Loops in CSS Preprocessors An Interview with Miriam Suzanne Estrogentrification Miriam, a how-to guide Holes / SideSaddle midwest tour Underground music showcase Species of the stars PROPHETIA VETITUM MUNDI Pig Sez, song demo I UMS day 4 (the end) UMS day 3 A Dark Plain, song demo UMS day 2 UMS day 1 Media Archeology Lab, Artist in Residence Stratified design (re)Thinking on your feet Five(5), song demo Poetry readings are terrible Explosive growth Get curious The Posture of Contour Starting from a seed Portrait of Sondra & Dan Creative modes and cycles Ordinary tools of thought Portrait of Kitten Karlyle (nsfw) Fuck the muse Susy 1.0 release
Javascript automation on Mac
2022-12-11 · via Miriam Eric Suzanne

I’ve been using Alfred for Mac as long as I can remember – occasionally installing ‘powerpack’ workflows or building simple flows with the graphic interface. The other day, I discovered one of my third-party workflows wasn’t working. It’s a word/character counter that I don’t use often, but like to have available.

Digging into it, I found a simple php script defining the entire word-count logic. That’s interesting, I didn’t know you could write Alfred workflows in php. I wonder what other languages are supported? Here’s the list provided in a dropdown:

  • /bin/bash
  • /bin/zsh
  • /usr/bin/php [not installed]
  • /usr/bin/ruby
  • /usr/bin/python [not installed]
  • /usr/bin/python3
  • /usr/bin/perl
  • /usr/bin/osascript (AppleScript)
  • /usr/bin/osascript (JavaScript)
  • /usr/bin/swift

Well, that explains why the php script wasn’t working – it must have broken when I got my new Mac. But JavaScript support means I can re-write this workflow myself, without learning a new language?

Yes! It turns out Apple now supports JavaScript for Automation as an alternative to AppleScript. You can do this in Automator as well as Alfred.

The basics of JS in Alfred

After selecting /usr/bin/osascript (JavaScript) from the language dropdown, I left the next option as-is: with input as {query}. That gives me the input pasted to Alfred.

For output, the docs recommend returning a JSON object. The object has a single items key, with an array of objects for each result row to be displayed. The essential properties of an item seem to be the title and arg keys. There’s more you can provide, but that’s enough to get started.

  • The title is what’s actually shown in the row
  • The arg is the value that gets passed along to any further actions (like copying to clipboard)

In my case, the result I want is:

{"items": [
  {
    "title": "Words: <word-count>",
    "arg": "<word-count>"
  },
  {
    "title": "Chars: <char-count>",
    "arg": "<char-count>"
  }
]}

There doesn’t seem to be much magic around using the {query} or returning the JSON. If we define a function called wordCounter() that accepts a single argument and returns a JSON string, we can run it like this:

wordCounter(`{query}`);

The {query} itself seems to be supplied as a direct text replacement before the script is run. If I remove the backticks or quotes around {query}, it assumes the first word is an undefined JS variable and throws an error.

My simple word counter

I didn’t put a lot of thought into edge cases beyond ‘the query is missing for some reason’, so we’ll see how well it holds up. Here’s the logic I used for counting:

const words = (text || '').trim().split(' ').length;
const chars = (text || '').length;

Nothing clever, and it seems to work even when I copy text with line-breaks – so that’s good enough for now. The rest is just to make sure the query is a string (maybe unnecessary since I’m already forcing it), and build the correct JSON from the results. Here’s the full script:

// generate an Alfred return item
const item = (title, arg) => ({
  title: arg ? `${title}: ${arg}` : title,
  arg,
});

// count words/chars and return as items
const count = (text) => {
  const words = (text || '').trim().split(' ').length;
  const chars = (text || '').length;

  return [
    item('Words', words),
    item('Chars', chars),
  ];
}

// count or error, and return as JSON string
const wordCounter = (txt) => {
  // error if query isn't text (maybe overkill?)
  const items = (typeof txt === 'string')
    ? count(txt)
    : [item('ERROR: please provide a string', null),];

  return JSON.stringify({ items });
}

// run the script
wordCounter(`{query}`);

That works great so far. The only other thing in the workflow is copying the output to the clipboard.

Now that I know how to do it, I wonder what other automations I might want to write!