Full Code of titoBouzout/WordCount for AI

st3 41248f11f459 cached
7 files
16.4 KB
4.6k tokens
21 symbols
1 requests
Download .txt
Repository: titoBouzout/WordCount
Branch: st3
Commit: 41248f11f459
Files: 7
Total size: 16.4 KB

Directory structure:
gitextract_h9em282t/

├── .github/
│   └── FUNDING.yml
├── .gitignore
├── Main.sublime-menu
├── WordCount.py
├── WordCount.sublime-settings
├── license.txt
└── readme.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [titoBouzout] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .gitignore
================================================
push.bat
*.pyc
package-metadata.json

================================================
FILE: Main.sublime-menu
================================================
[
    {
        "mnemonic": "n",
        "caption": "Preferences",
        "id": "preferences",
        "children": [
            {
                "mnemonic": "P",
                "caption": "Package Settings",
                "id": "package-settings",
                "children": [
                    {
                        "caption": "Word Count",
                        "children": [
                            {
                                "caption": "Settings",
                                "command": "edit_settings",
                                "args": {
                                    "base_file": "${packages}/WordCount/WordCount.sublime-settings",
                                    "default": "{\n$0\n}\n"
                                }
                            }
                        ]
                    }
                ]
            }
        ]
    }
]


================================================
FILE: WordCount.py
================================================
import sublime, sublime_plugin, re
import time
import threading
from math import ceil as ceil
from os.path import basename

Pref = {}
s = {}
wsd = {'modified':True, 'selection':True, 'syntax':'plain text','changes':-1,'status':-1}

def plugin_loaded():
	global s, Pref
	s = sublime.load_settings('WordCount.sublime-settings')
	Pref = Pref()
	Pref.load();
	s.clear_on_change('reload')
	s.add_on_change('reload', lambda:Pref.load())

	if not 'running_word_count_loop' in globals():
		global running_word_count_loop
		running_word_count_loop = True
		t = threading.Thread(target=word_count_loop)
		t.start()

class Pref:
	def load(self):
		Pref.view                   = False
		Pref.elapsed_time           = 0.4
		Pref.running                = False

		Pref.wrdRx                  = re.compile(s.get('word_regexp', "^[^\w]?`*\w+[^\w]*$"), re.U)
		Pref.wrdRx                  = Pref.wrdRx.match
		Pref.splitRx                = s.get('word_split', None)
		if Pref.splitRx:
			Pref.splitRx            = re.compile(Pref.splitRx, re.U)
			Pref.splitRx            = Pref.splitRx.findall

		Pref.enable_live_count      = s.get('enable_live_count', True)
		Pref.enable_readtime        = s.get('enable_readtime', False)
		Pref.enable_line_word_count = s.get('enable_line_word_count', False)
		Pref.enable_line_char_count = s.get('enable_line_char_count', False)
		Pref.enable_count_lines     = s.get('enable_count_lines', False)
		Pref.enable_count_chars     = s.get('enable_count_chars', False)
		Pref.enable_count_pages     = s.get('enable_count_pages', True)

		Pref.words_per_page         = s.get('words_per_page', 300)
		Pref.page_count_mode_count_words = s.get('page_count_mode_count_words', True)
		Pref.char_ignore_whitespace = s.get('char_ignore_whitespace', True)
		Pref.readtime_wpm           = s.get('readtime_wpm', 200)
		Pref.whitelist              = [x.lower() for x in s.get('whitelist_syntaxes', []) or []]
		Pref.blacklist              = [x.lower() for x in s.get('blacklist_syntaxes', []) or []]
		Pref.strip                  = s.get('strip', [])

		for window in sublime.windows():
			for view in window.views():
				view.erase_status('WordCount');
				view.settings().erase('WordCount')

class WordCount(sublime_plugin.EventListener):

	def should_run_with_syntax(self, view):
		vs =  view.settings()

		syntax = vs.get('syntax')
		syntax = basename(syntax).split('.')[0].lower() if syntax != None else "plain text"

		ws = vs.get('WordCount', wsd)
		ws['syntax'] = syntax
		vs.set('WordCount', ws)

		if len(Pref.blacklist) > 0:
			for white in Pref.blacklist:
				if white == syntax:
					view.erase_status('WordCount');
					return False
		if len(Pref.whitelist) > 0:
			for white in Pref.whitelist:
				if white == syntax:
					return True
			view.erase_status('WordCount');
			return False
		return True

	def on_activated_async(self, view):
		self.asap(view)

	def on_post_save_async(self, view):
		self.asap(view)

	def on_modified_async(self, view):
		vs = view.settings()
		ws = vs.get('WordCount', wsd)
		ws['modified'] = True
		vs.set('WordCount', ws)

	def on_selection_modified_async(self, view):
		vs = view.settings()
		ws = vs.get('WordCount', wsd)
		ws['selection'] =  True
		vs.set('WordCount', ws)

	def on_close(self, view):
		Pref.view = False

	def asap(self, view):
		Pref.view = view
		Pref.elapsed_time = 0.4
		sublime.set_timeout(lambda:WordCount().run(True), 0)

	def run(self, asap = False):
		if not Pref.view:
			self.guess_view()
		else:
			view = Pref.view
			vs = view.settings()
			ws = vs.get('WordCount', wsd)
			if vs.get('is_widget') or not ws: # (if not ws)WTF, happens when closing a view
				self.guess_view()
			else:
				if (ws['modified'] or ws['selection']) and (Pref.running == False or asap) and self.should_run_with_syntax(view):
					sel = view.sel()
					if sel:
						if len(sel) == 1 and sel[0].empty():
							if not Pref.enable_live_count or view.size() > 10485760:
								view.erase_status('WordCount')
							elif view.change_count() != ws['changes']:
								ws['changes'] = view.change_count()
								#  print('running:'+str(view.change_count()))
								WordCountThread(view, [view.substr(sublime.Region(0, view.size()))], view.substr(view.line(view.sel()[0].end())), False).start()
							else:
								# print('running from cache:'+str(view.change_count()))
								view.set_status('WordCount', self.makePlural('Word', ws['count'] ))
						else:
							try:
								WordCountThread(view, [view.substr(sublime.Region(s.begin(), s.end())) for s in sel], view.substr(view.line(view.sel()[0].end())), True).start()
							except:
								pass
						ws['modified'] = False
						ws['selection'] = False
						vs.set('WordCount', ws)


	def guess_view(self):
		if sublime.active_window() and sublime.active_window().active_view():
			Pref.view = sublime.active_window().active_view()

	def display(self, view, on_selection, word_count, char_count, word_count_line, char_count_line):

		m = int(word_count / Pref.readtime_wpm)
		s = int(word_count % Pref.readtime_wpm / (Pref.readtime_wpm / 60))

		status = []

		if word_count:
			status.append(self.makePlural('Word', word_count))

		if Pref.enable_count_chars and char_count > 0:
			status.append(self.makePlural('Char', char_count))

		if Pref.enable_line_word_count and word_count_line > 1:
			status.append( "%d Words in Line" % (word_count_line))

		if Pref.enable_line_char_count and char_count_line > 1:
			status.append("%d Chars in Line" % (char_count_line))

		if Pref.enable_count_lines:
			lines = (view.rowcol(view.size())[0] + 1)
			if lines > 1:
				status.append('%d Lines' % (view.rowcol(view.size())[0] + 1))

		if Pref.enable_count_pages and word_count > 0:
			if not Pref.page_count_mode_count_words or Pref.words_per_page < 1:
				visible = view.visible_region()
				rows_per_page = (view.rowcol(visible.end())[0]) - (view.rowcol(visible.begin())[0])
				pages = ceil((view.rowcol(view.size()-1)[0] + 1 ) /  rows_per_page)
				current_line = view.rowcol(view.sel()[0].begin())[0]+1
				current_page = ceil(current_line / rows_per_page)
			else:
				pages = ceil(word_count / Pref.words_per_page)
				rows = view.rowcol(view.size()-1)[0] + 1
				current_line = view.rowcol(view.sel()[0].begin())[0]+1
				current_page = ceil((current_line / Pref.words_per_page) / (rows / Pref.words_per_page))

			if pages > 1:
				if current_page != 0:
					status.append('Page '+str(current_page)+'/'+str(pages))
				else:
					status.append('Page '+str(current_page)+'/'+str(pages))

		if Pref.enable_readtime and s >= 1:
			status.append("~%dm %ds reading time" % (m, s))

		view.set_status('WordCount', ', '.join(status))

	def makePlural(self, word, count):
		return "%s %s%s" % (count, word, ("s" if count != 1 else ""))

class WordCountThread(threading.Thread):

	def __init__(self, view, content, content_line, on_selection):
		threading.Thread.__init__(self)
		self.view = view
		self.content = content
		self.content_line = content_line
		self.on_selection = on_selection

		self.char_count = 0
		self.word_count_line = 0
		self.chars_in_line = 0

		ws = view.settings().get('WordCount', wsd)
		self.syntax = ws['syntax']

	def run(self):
		# print ('running:'+str(time.time()))
		Pref.running         = True

		if self.syntax and self.syntax in Pref.strip:
			for item in Pref.strip[self.syntax]:
				for k in range(len(self.content)):
					self.content[k] = re.sub(item, '', self.content[k])
				self.content_line = re.sub(item, '', self.content_line)

		self.word_count      = sum([self.count(region) for region in self.content])

		if Pref.enable_count_chars:
			if Pref.char_ignore_whitespace:
				self.char_count  = sum([len(''.join(region.split())) for region in self.content])
			else:
				self.char_count  = sum([len(region) for region in self.content])

		if Pref.enable_line_word_count:
			self.word_count_line = self.count(self.content_line)

		if Pref.enable_line_char_count:
			if Pref.char_ignore_whitespace:
				self.chars_in_line = len(''.join(self.content_line.split()))
			else:
				self.chars_in_line = len(self.content_line)

		if not self.on_selection:
			vs = self.view.settings()
			ws = vs.get('WordCount', wsd)
			ws['count'] = self.word_count
			vs.set('WordCount', ws)

		sublime.set_timeout(lambda:self.on_done(), 0)

	def on_done(self):
		try:
			WordCount().display(self.view, self.on_selection, self.word_count, self.char_count, self.word_count_line, self.chars_in_line)
		except:
			pass
		Pref.running = False

	def count(self, content):

		# begin = time.time()

		#=====1
		# wrdRx = Pref.wrdRx
		# """counts by counting all the start-of-word characters"""
		# # regex to find word characters
		# matchingWrd = False
		# words = 0
		# space_symbols = [' ', '\r', '\n']
		# for ch in content:
		# # 	# test if this char is a word char
		# 	isWrd = ch not in space_symbols
		# 	if isWrd and not matchingWrd:
		# 		words = words + 1
		# 		matchingWrd = True
		# 	if not isWrd:
		# 		matchingWrd = False

		#=====2
		wrdRx = Pref.wrdRx
		splitRx = Pref.splitRx
		if splitRx:
			words = len([1 for x in splitRx(content) if False == x.isdigit() and wrdRx(x)])
		else:
			words = len([1 for x in content.replace("'", '').replace('—', ' ').replace('–', ' ').replace('-', ' ').split() if False == x.isdigit() and wrdRx(x)])

		# Pref.elapsed_time = end = time.time() - begin;
		# print ('Benchmark: '+str(end))

		return words

def word_count_loop():
	word_count = WordCount().run
	while True:
		# sleep time is adaptive, if takes more than 0.4 to calculate the word count
		# sleep_time becomes elapsed_time*3
		if Pref.running == False:
			sublime.set_timeout(lambda:word_count(), 0)
		time.sleep((Pref.elapsed_time*3 if Pref.elapsed_time > 0.4 else 0.4))

================================================
FILE: WordCount.sublime-settings
================================================
{
	"enable_live_count": true,

	"enable_readtime": false,
	"readtime_wpm": 200,
	"char_ignore_whitespace": true,

	"enable_line_word_count": false,
	"enable_line_char_count": false,

	"enable_count_chars": false,
	"enable_count_lines": false,

	"enable_count_pages": true,
	"words_per_page": 300,
	"page_count_mode_count_words": true,

	"whitelist_syntaxes": [],
	"blacklist_syntaxes": ["CSS", "SQL", "JavaScript", "Python", "PHP", "JSON"],

	/* please use lowercase for the syntax names in the following section: */
	"strip": {
		"php": [
			"<[^>]*>"
		],
		"html": [
			"<[^>]*>"
		]
	}
}

================================================
FILE: license.txt
================================================
"None are so hopelessly enslaved as those who falsely believe they are free."
                                              Johann Wolfgang von Goethe

Copyright (C) 2012 Tito Bouzout <tito.bouzout@gmail.com>

This license apply to all the files inside this program unless noted
different for some files or portions of code inside these files.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation. http://www.gnu.org/licenses/gpl.html

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/gpl.html

================================================
FILE: readme.md
================================================


## Description

Provides a real-time Word Count and character count in the status-bar for Sublime Text. See: http://www.sublimetext.com/

Count words and/or characters on document or in selections. By default, whitespace is not included in the character count.

The minimal word length is 1 and does not count digits.

An estimated reading time is now appended to the end of the word count.

## Installation

Zipped file:
1. Locate the Packages directory for Sublime Text.
2. Download the zipped contents of this repository into Packages.
3. Unzip the zipped file. It will create a new directory in Packages.
4. Re-start Sublime Text.

Cloned files:
1. Locate the Packages directory for Sublime Text.
2. In the Packages directory, create a sub-directory called WordCount.
3. Clone the contents of this repository to your new WordCount folder.
4. Re-start Sublime Text.

## Preferences
Located under Sublime Text>Preferences>Package Settings>Settings — User
(You probably need to copy the default settings from the uneditable Sublime Text>Preferences>Package Settings>Settings — **Default**)

 - `enable_live_count` : true

		Allows to control if the live word counter is enabled. Otherwise will be enabled for selections only.

 - `enable_readtime` : false

		Allows you to control if the estimated reading time is enabled.
		Reading time is only displayed when there is a time > 1s.

 - `readtime_wpm` : 200

		Sets the WPM to calculate the Estimated Reading Time for the file.

 - `whitelist_syntaxes` : []

		An array of syntax names that WordCount should run on.
		Example: ["Plain text", "Markdown"]
		If the array is empty, like it is by default, WordCount will run on any syntax.

 - `blacklist_syntaxes` : []

		An array of syntax names that WordCount should not run on.
		Example: ["Plain text", "Markdown"]
		If the array is empty, like it is by default, WordCount will run on any syntax.

 - `char_ignore_whitespace` : true

		Whether to skip whitespace for the character count.

 - `enable_line_word_count` : false

		Display the count of words found on current line.

 - `enable_line_char_count` : false

		Display the count of characters found on current line.

 - `enable_count_lines` : false

		Display the number of lines in file

 - `enable_count_chars` : false

		Display the number of characters in file

 - `enable_count_pages` : true

		Display the number of pages in file

 - `page_count_mode_count_words` : true

		Sets the page count mode to words per page

 - `words_per_page` : 300

		Sets the number of words per page used to calculate number of pages

 - `word_regexp` : ""

		Word Regular expression. Defaults empty, an internal regular expression is used. If the portion of text matches this RegExp then the word is counted.

 - `word_split` : ""

		Split portions of text to test later as words with a Regular expression. Defaults to String.split() with no arguments, means that content will trim() and empty values (all whitespaces) are not used. In case of containing some value different than empty, the return of "re.findall" will be used.

 - `split`: {}

		Remove regex patterns by syntax. Use lowercase for the syntax names.

		Example to ignore all tags, including comments, from HTML:

		```
		"strip": {
			"html": [
				"<[^>]*>"
			]
		}
		```

## Inspiration

 - The main loop inspired by sublimelint https://github.com/lunixbochs/sublimelint
 - The count inspired by the original WordCount plugin http://code.google.com/p/sublime-text-community-packages/source/browse/#svn%2Ftrunk%2FWordCount committed by mindfiresoftware

## Contributors

 - Liam Cain
 - Lee Grey
 - Hawken Rives
 - Yaw Anokwa
 - James Brooks
 - Antony Male
 - Alex Galonsky
 - RikkiMongoose
 - ChrisJefferson
 - Harry Ng. (From [Word Count Tool](http://wordcounttools.com/))
 - MangleKuo
 - Nick Cody
 - Amanda Neumann
Download .txt
gitextract_h9em282t/

├── .github/
│   └── FUNDING.yml
├── .gitignore
├── Main.sublime-menu
├── WordCount.py
├── WordCount.sublime-settings
├── license.txt
└── readme.md
Download .txt
SYMBOL INDEX (21 symbols across 1 files)

FILE: WordCount.py
  function plugin_loaded (line 11) | def plugin_loaded():
  class Pref (line 25) | class Pref:
    method load (line 26) | def load(self):
  class WordCount (line 59) | class WordCount(sublime_plugin.EventListener):
    method should_run_with_syntax (line 61) | def should_run_with_syntax(self, view):
    method on_activated_async (line 84) | def on_activated_async(self, view):
    method on_post_save_async (line 87) | def on_post_save_async(self, view):
    method on_modified_async (line 90) | def on_modified_async(self, view):
    method on_selection_modified_async (line 96) | def on_selection_modified_async(self, view):
    method on_close (line 102) | def on_close(self, view):
    method asap (line 105) | def asap(self, view):
    method run (line 110) | def run(self, asap = False):
    method guess_view (line 143) | def guess_view(self):
    method display (line 147) | def display(self, view, on_selection, word_count, char_count, word_cou...
    method makePlural (line 195) | def makePlural(self, word, count):
  class WordCountThread (line 198) | class WordCountThread(threading.Thread):
    method __init__ (line 200) | def __init__(self, view, content, content_line, on_selection):
    method run (line 214) | def run(self):
    method on_done (line 249) | def on_done(self):
    method count (line 256) | def count(self, content):
  function word_count_loop (line 289) | def word_count_loop():
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (19K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 813,
    "preview": "# These are supported funding model platforms\n\ngithub: [titoBouzout] # Replace with up to 4 GitHub Sponsors-enabled user"
  },
  {
    "path": ".gitignore",
    "chars": 36,
    "preview": "push.bat\n*.pyc\npackage-metadata.json"
  },
  {
    "path": "Main.sublime-menu",
    "chars": 903,
    "preview": "[\n    {\n        \"mnemonic\": \"n\",\n        \"caption\": \"Preferences\",\n        \"id\": \"preferences\",\n        \"children\": [\n  "
  },
  {
    "path": "WordCount.py",
    "chars": 9716,
    "preview": "import sublime, sublime_plugin, re\nimport time\nimport threading\nfrom math import ceil as ceil\nfrom os.path import basena"
  },
  {
    "path": "WordCount.sublime-settings",
    "chars": 591,
    "preview": "{\n\t\"enable_live_count\": true,\n\n\t\"enable_readtime\": false,\n\t\"readtime_wpm\": 200,\n\t\"char_ignore_whitespace\": true,\n\n\t\"enab"
  },
  {
    "path": "license.txt",
    "chars": 924,
    "preview": "\"None are so hopelessly enslaved as those who falsely believe they are free.\"\n                                          "
  },
  {
    "path": "readme.md",
    "chars": 3837,
    "preview": "\n\n## Description\n\nProvides a real-time Word Count and character count in the status-bar for Sublime Text. See: http://ww"
  }
]

About this extraction

This page contains the full source code of the titoBouzout/WordCount GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (16.4 KB), approximately 4.6k tokens, and a symbol index with 21 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!