• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Github每日精选第91期macOS 剪贴板管理器Maccy

武飞扬头像
go2coding
帮助1

Maccy

Maccy 是一个轻量级的 macOS 剪贴板管理器。它保留了您复制内容的历史记录,让您可以快速导航、搜索和使用以前的剪贴板内容。

Maccy适用于 macOS Mojave 10.14 或更高版本。

学新通
github的地址在这里

代码分析

Maccy 的使用非常的方便,用户界面也非常的简单,他的代码量并不多,大部分都是使用swift写成,可以用来做swift入门的练习,做起来应该非常的有意思。

监控剪切板的变化:

private func start() {
    statusItem.behavior = .removalAllowed
    statusItem.isVisible = UserDefaults.standard.showInStatusBar
    statusItem.menu = menuLoader

    if let button = statusItem.button {
      button.image = NSImage(named: "StatusBarMenuImage")
      button.imagePosition = .imageRight
      (button.cell as? NSButtonCell)?.highlightsBy = []
    }

    clipboard.onNewCopy(history.add)
    clipboard.onNewCopy(menu.add)
    clipboard.onNewCopy(updateMenuTitle)
    clipboard.startListening()

    populateHeader()
    populateItems()
    populateFooter()

    updateStatusItemEnabledness()
  }
学新通

onNewCopy 是一个事件,当截切板的内容有变化的时候,historymenu,updateMenuTitle都会跟着变化,所有比较核心的部分其实就是获取剪切板的变化情况了,一旦我们能知道剪切板的情况,很多事情就是逻辑的问题了。

历史记录:

func add(_ item: HistoryItem) {
    if let existingHistoryItem = findSimilarItem(item) {
      item.contents = existingHistoryItem.contents
      item.firstCopiedAt = existingHistoryItem.firstCopiedAt
      item.numberOfCopies  = existingHistoryItem.numberOfCopies
      item.pin = existingHistoryItem.pin
      item.title = existingHistoryItem.title
      item.application = existingHistoryItem.application
      remove(existingHistoryItem)
    } else {
      if UserDefaults.standard.playSounds {
        NSSound(named: NSSound.Name("write"))?.play()
      }
    }

    CoreDataManager.shared.saveContext()
  }
学新通

历史记录在剪切板变化的时候,会有所变化,这里直接保存在数据库CoreDataManager中。在一开始程序启动的时候,会加载历史的数据。

搜索

搜索部分的算法,使用的是模糊搜索和普通的搜索,对于字符串的搜索,这里还是比较暴力的,并没有对这方面的内容做优化,可能历史记录并不会太多,所有搜索速度不会收到影响。

private func fuzzySearch(string: String, within: [Searchable]) -> [SearchResult] {
    let pattern = fuse.createPattern(from: string)
    let searchResults: [SearchResult] = within.compactMap({ item in
      fuzzySearch(for: pattern, in: item.title, of: item) ??
        fuzzySearch(for: pattern, in: item.value, of: item)
    })
    let sortedResults = searchResults.sorted(by: { ($0.score ?? 0) < ($1.score ?? 0) })
    return sortedResults
  }

  private func fuzzySearch(for pattern: Fuse.Pattern?, in searchString: String, of item: Searchable) -> SearchResult? {
    var searchString = searchString
    if searchString.count > fuzzySearchLimit {
      // shortcut to avoid slow search
      let stopIndex = searchString.index(searchString.startIndex, offsetBy: fuzzySearchLimit)
      searchString = "\(searchString[...stopIndex])"
    }

    if let fuzzyResult = fuse.search(pattern, in: searchString) {
      return SearchResult(
        score: fuzzyResult.score,
        object: item,
        titleMatches: fuse.search(pattern, in: item.title)?.ranges ?? []
      )
    } else {
      return nil
    }
  }

  private func simpleSearch(string: String, within: [Searchable]) -> [SearchResult] {
    return within.compactMap({ item in
      simpleSearch(for: string, in: item.title, of: item) ??
        simpleSearch(for: string, in: item.value, of: item)
    })
  }

  private func simpleSearch(for string: String, in searchString: String, of item: Searchable) -> SearchResult? {
    if searchString.range(
      of: string,
      options: .caseInsensitive,
      range: nil,
      locale: nil
    ) != nil {
      var result = SearchResult(
        score: nil,
        object: item,
        titleMatches: []
      )

      let title = item.title
      if let titleRange = title.range(of: string, options: .caseInsensitive, range: nil, locale: nil) {
        let lowerBound = title.distance(from: title.startIndex, to: titleRange.lowerBound)
        let upperBound = title.distance(from: title.startIndex, to: titleRange.upperBound) - 1
        result.titleMatches.append(lowerBound...upperBound)
      }

      return result
    } else {
      return nil
    }
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhibcicj
系列文章
更多 icon
同类精品
更多 icon
继续加载