This commit is contained in:
Dimitris Marakomihelakis 2023-08-20 20:37:24 +03:00
parent 175316f9a4
commit a569cef447
17 changed files with 903 additions and 46 deletions

34
.shellnotes.sh Executable file
View file

@ -0,0 +1,34 @@
#The first line is the user's default shell found during installation process.
#The lines below must NOT be changed.
export DIR=$(pwd)
. ~/.shellnotes/whatsnew.sh
. ~/.shellnotes/util/getv.sh
. ~/.shellnotes/def/defaults.sh
. ~/.shellnotes/util/ChMkDir.sh
. ~/.shellnotes/util/quickread.sh
. ~/.shellnotes/util/quicknote.sh
. ~/.shellnotes/util/newnote.sh
. ~/.shellnotes/util/readnote.sh
. ~/.shellnotes/util/delnote.sh
. ~/.shellnotes/util/listnotes.sh
. ~/.shellnotes/util/findnote.sh
. ~/.shellnotes/util/findmisplacednote.sh
. ~/.shellnotes/util/renamenote.sh
. ~/.shellnotes/util/notewc.sh
. ~/.shellnotes/util/notegrep.sh
. ~/.shellnotes/util/clipnote.sh
. ~/.shellnotes/util/rmdups.sh
. ~/.shellnotes/util/shellnotes.sh
. ~/.shellnotes/util/.hidden/.clearlogs.sh
. ~/.shellnotes/util/.hidden/.resetshellnotes.sh

View file

@ -5,7 +5,18 @@ Released under the "All rights reserved" category. See the RIGHTS.txt file
in /docs/github/ for its full text.
info
NOTES_EDITOR="$(eval cat ~/.shellnotes/util/shellnotes/sd/sd-input1.txt)"
if [ $(cat "$HOME/.shellnotes/util/shellnotes/sd/sd-input1.txt") = ".shellnotes/sne/sne.py" ]; then
function NOTES_EDITOR() {
if [ -n "$1" ]; then
python3 $(cat $HOME/.shellnotes/util/shellnotes/sd/sd-input1.txt) "$1"
else
python3 $(cat $HOME/.shellnotes/util/shellnotes/sd/sd-input1.txt)
fi
}
else
NOTES_EDITOR() { eval cat $HOME/.shellnotes/util/shellnotes/sd/sd-input1.txt }
fi
QUICK_NOTES_EDITOR="$(eval cat ~/.shellnotes/util/shellnotes/sd/sd-input2.txt)"
DEFAULT_PATH="$(eval echo $(cat ~/.shellnotes/util/shellnotes/sd/sd-input3.txt))"

View file

@ -1,23 +0,0 @@
# Security Policy
## Supported Versions of shellnotes
| Version | Supported |
| ------- | ------------------ |
| 3.0.x | yes |
| 2.5.x | yes* |
| 2.3.x | yes* |
| 2.0.x | yes* |
| 1.2.x | yes* |
| 1.1.x | yes* |
| 1.0.x | no |
| 0.1.x | no |
*: Installation not supported
## About updating
Every new update is uploaded in this page.
If you want to check your version, type "shellnotes -v" and check if the version is supported.

View file

@ -4,32 +4,32 @@ how to set defaults
In shellnotes v.3.0 and later, there is a more dynamic and safe way of setting your default notes editors and folder.
Changing both default note editors and Note folder with the sd system:
-For <3.0 users, the command "shellnotes -sd" or "shellnotes --set-defaults" will redirect the user to set_defaults.sh, where he will be able to configure the default editors and folder safer, faster and more dynamically.
Changing both default note editors and Note folder with the -sd parameter:
-For <3.0 users, the command "shellnotes -sd" or "shellnotes --set-defaults" will run ~/.shellnotes/set_defaults.sh, where the user will be able to configure the default editors and folder.
Step by step instructions to change defaults with sd:
1. After installing shellnotes, run "shellnotes --set-defaults" in your terminal.
2. You will be redirected to ~/.shellnotes/set_defaults.sh, a runnable script. Select an option:
2. Select an option:
1. Change default regular notes editor:
Regular notes are taken with newnote() and read with readnote().
Select option 1 and enter the name of the program. It should be a valid name and not a path.
Select option 1 and enter the name of the program. It should be a valid name and not a path. (i.e. "subl")
2. Change default quick notes editor:
Regular notes are taken with quicknote() and read with quickread().
Select option 2 and enter the name of the program. It should be a valid name and not a path.
Select option 2 and enter the name of the program. It should be a valid name and not a path. (i.e. "nano")
3. Change default notes folder:
All shellnotes' commands use the $DEFAULT_PATH variable to save, read, delete, rename notes.
This means that the Notes folder to store your notes must be a valid path.
The default notes folder as you may know is ~/Notes and is created at first terminal launch with shellnotes installed.
The default notes folder is ~/Notes and is created at first terminal launch with shellnotes installed.
Select option 3 and enter the full path of the directory. It should be a valid absolute path and not a relative one.
4. View defaults:
sd gives the user the option to also view current defaults.
-sd gives the user the option to also view current defaults.
Select option 4 and take a look at your defaults.
3. When you're done, restart your terminal and the defaults will have been changed.
WARNING: If a name or a path is not valid in step 2, you will be reminded by the script and the
3. When you're done, restart your terminal and the defaults will change.
WARNING: If a name or a path is not valid in step 2, the
setting will fail.
For 3.0 and earlier users: (text from help page)
For 3.0 and earlier:
Changing default editors manually:
@ -41,14 +41,14 @@ Changing default editors manually:
problems may occur.
Default editors:
for newnote: gedit (ubuntu default)
for newnote: SnE (Shellnotes Notes Editor, installed by default)
for quicknote: nano (in-terminal experience)
Suggested editors other than default:
for newnote: Sublime text, Atom
for newnote: Sublime text, Atom, gedit
for quicknote: Vim
Changing default Notes Folder manually:
Changing default folder manually is a feature enabled in shellnotes <2.5. In case the user wants to change the default folder to store/write/list/rename/read/delete his notes, he must change the DEFAULT_PATH value from defaults.sh in ~/.shellnotes/def/. This is a variable that the rest of the code uses to check the default folder for all the commands to make change in the right directory. This means that if you change the name of the path the variable is going to search for, the code will use your prefered folder. In case the path is incorrect, problems may occur.
Changing default folder manually is a possible in shellnotes <2.5. In case the user wants to change the default folder to store/write/list/rename/read/delete his notes, he must change the DEFAULT_PATH value from defaults.sh in ~/.shellnotes/def/. This is a variable that the rest of the code uses to check the default folder for all the commands to make change in the right directory. This means that if you change the name of the path the variable is going to search for, the code will use your prefered folder. In case the path is incorrect, problems may occur.
Default path:
Home/Notes/

141
docs/sne.md Normal file
View file

@ -0,0 +1,141 @@
# SnE - Shellnotes Notes Editor Documentation
## Table of Contents
1. [Introduction](#introduction)
2. [Features](#features)
3. [Integration with Shellnotes](#integration-with-shellnotes)
4. [Usage](#usage)
5. [Logging System](#logging-system)
6. [Tools](#tools)
7. [Pasting Notes](#pasting-notes)
8. [Conclusion](#conclusion)
## Introduction <a name="introduction"></a>
SnE (Shellnotes Notes Editor) is a text editor developed as part of the Shellnotes Project. Shellnotes is a terminal-based note-taking tool for Linux users. SnE provides users with a graphical interface to create, edit, and manage their notes efficiently via a user-friendly text editor. SnE is built using the Tkinter library and offers various features to enhance the note-taking experience.
## Features <a name="features"></a>
SnE comes equipped with several features to facilitate note-taking and editing:
- **Graphical User Interface:** SnE offers a graphical interface for creating and editing notes, making it user-friendly and accessible.
- **Text Editing:** Users can input and edit text using standard text editing functionalities such as copy, paste, undo, redo, and find.
- **Styling Options:** SnE allows users to customize the font family, font size, and font weight of their notes for better readability and personalization.
- **Themes:** Users can choose from a selection of themes to customize the appearance of the editor to their liking.
- **Character Count:** SnE displays a live character count at the bottom of the editor to help users keep track of their note length.
- **Spell Check:** The editor includes a spell check feature that highlights misspelled words and suggests corrections.
- **Text-to-Speech:** SnE can read selected text or the entire note aloud using a text-to-speech engine.
- **Integration:** SnE seamlessly integrates with Shellnotes, allowing users to create and manage notes directly from their terminal, using the `newnote` command.
## Integration with Shellnotes <a name="integration-with-shellnotes"></a>
Users can launch SnE from the terminal using the command `newnote`, but they can also use it as a regular text editor by typing `NOTES_EDITOR` into the terminal.
## Usage <a name="usage"></a>
To launch SnE and start creating/editing notes, follow these steps:
1. Open your terminal.
2. Navigate to the directory where you have Shellnotes installed.
3. Use the appropriate command to launch SnE:
`newnote`
4. The SnE window will appear, providing a text editor interface.
5. Use the available features (copy, paste, save, etc.) to create and edit your notes.
6. Customize the editor's font style, size, weight, and theme according to your preferences.
7. When you're done editing, save your note and close SnE.
## Logging System <a name="logging-system"></a>
SnE incorporates a logging system to track events and errors. The log files are stored in the user's home directory under `~/.shellnotes/logs/sne`. The logging system helps diagnose issues, monitor usage, and improve the overall stability of the application. This is achieved by the help of the python-loguru library.
## Tools <a name="tools"></a>
### Text-to-Speech (Read Aloud)
SnE provides a convenient Text-to-Speech (TTS) feature that allows you to have your notes read aloud. This feature is especially useful for proofreading, reviewing content, or simply listening to your notes. SnE uses the `pyttsx3` library to enable the TTS functionality.
**Usage:**
1. Select the text you want to hear read aloud within the editor.
2. Click on the "Tools" menu.
3. Choose the "Read Aloud" option.
4. The selected text will be converted into speech and played through your system's audio output.
### Search & Replace (Using `notegrep`)
SnE incorporates a powerful search and replace functionality using the `notegrep` tool. This tool allows you to search for specific patterns within your notes and replace them with new content. `notegrep` leverages regular expressions to perform advanced searches and replacements.
**Usage:**
1. Click on the "Tools" menu.
2. Select "Find" to search for specific text within the note. You can enter a keyword or phrase to search for.
3. Choose "Replace All..." to initiate a search and replace operation. This option lets you replace all occurrences of a particular text with a new value.
4. A separate window will appear, allowing you to specify the search pattern and the replacement text using regular expressions.
5. Once you've configured the search and replacement, click the "Replace" button to perform the operation.
### Spell Check
SnE includes a built-in spell check tool that helps you identify and correct spelling errors in your notes. It uses the `enchant` library to check the spelling of words against a dictionary. Misspelled words are highlighted, so that corrections can be made easily.
**Usage:**
1. Click on the "Tools" menu.
2. Choose the "Spell Check" option.
3. The spell check tool will scan the entire note for spelling errors.
4. Any misspelled words will be highlighted, usually with a red background.
5. To correct a misspelled word, right-click on it, and you'll be presented with suggested corrections. Select the appropriate correction to update the word.
6. Once the spell check is complete, your note will be free of spelling errors.
These additional tools enhance the usability and functionality of SnE by offering capabilities such as text-to-speech conversion, advanced search and replace using regular expressions, and an integrated spell check feature. These tools contribute to an improved note-taking experience, ensuring accurate and high-quality content creation.
## Pasting Notes <a name="pasting-notes"></a>
SnE offers the ability to paste your notes to external services for sharing or backup purposes. It provides integration with both Pastebin and GitHub Gists.
### Pasting on Pastebin
To paste your note on Pastebin:
1. Click on the "Tools" menu.
2. Select "Paste on Pastebin."
3. A link to the Pastebin page containing your note will be displayed.
4. Optionally, click the "Copy" button to copy the link to your clipboard.
### Pasting on GitHub Gists
To paste your note on GitHub Gists:
1. Click on the "Tools" menu.
2. Select "Paste on Github Gists."
3. If prompted, ensure that your GitHub token (GH_TOKEN) is set using the `shellnotes --set-github-token` command.
4. A link to the GitHub Gist containing your note will be displayed.
5. Optionally, click the "Copy" button to copy the link to your clipboard.
> By default, uploaded notes are private, but you can make them public on demand.
## Conclusion <a name="conclusion"></a>
SnE (Shellnotes Notes Editor) enhances the Shellnotes experience by providing a feature-rich graphical interface for creating, editing, and managing notes. With its user-friendly design and integration with Shellnotes, SnE offers a seamless note-taking solution for Linux users. Its versatile features, logging system, and options to paste notes to external services make it a powerful tool for efficient note management.
For any issues, inquiries, or suggestions, please refer to the official Shellnotes documentation or reach out to the developer Dimitris Marakomichelakis.

View file

@ -10,11 +10,12 @@ Software requirements:
-curl
-git
-Python 3.5 or later
-GNU g++ compiler for c++ v.9.3.0 or later
-Solid Internet Connection required for updating (at least 5mbps)
*Note* All unmet software dependencies will be installed alongside shellnotes.
Hardware requirements (Minimum):
-Processor : Intel® Core™ i3-L13G4
-RAM : 700 MB
-HDD/SSD : 500 MB free space
-HDD/SSD : 400 MB free space

View file

@ -6,7 +6,7 @@ Released under the "All rights reserved" category. See the RIGHTS.txt file
in /docs/github/ for its full text.
info
VER_TO_INSTALL=3.5 #This is used when updating, it will be changed in every new update
VER_TO_INSTALL=4.0 #This is used when updating, it will be changed in every new update
if [ -e ~/.shellnotes/.shellnotes.sh ]; then
echo "Shellnotes is already installed."
echo "If you want to update, please run 'update.sh'."
@ -20,6 +20,7 @@ else
mv def ~/.shellnotes/
mv logs ~/.shellnotes/
mv ver ~/.shellnotes/
mv sne ~/.shellnotes/
mv image ~/.shellnotes/
mv shellnotes.sh ~/.shellnotes/.shellnotes.sh
mv $0 ~/.shellnotes/
@ -38,15 +39,26 @@ else
sudo cp ~/.shellnotes/docs/manpages/* /usr/local/man/man1/
sudo gzip -f /usr/local/man/man1/*.1
sudo mandb >/dev/null
sudo apt-get install xclip
sudo apt install python3
sudo apt install python3-pip
sudo apt install python3 -y
sudo apt install python3-pip -y
pip install pathlib
sudo apt update
sudo chmod a+x ~/.shellnotes/util/exec/*
sudo chmod +x ~/.shellnotes/.shellnotes.sh
clear
echo "Installing Shellnotes Note Editor (SnE)..."
echo "DEFAULT_PATH=$HOME" > ~/.shellnotes/sne/.env
#Install dependencies
pip install -r ~/.shellnotes/sne/requirements.txt
sudo apt-get install espeak -y
echo "$VER_TO_INSTALL" > ~/.shellnotes/ver/.shellnotes_version
if [ -n "`$SHELL -c 'echo $ZSH_VERSION'`" ]; then

View file

@ -71,6 +71,7 @@ elif [[ "$input" == "3" ]]; then
else
mv $DEFAULT_PATH/* $name
echo "$name" > ~/.shellnotes/util/shellnotes/sd/sd-input3.txt
echo "DEFAULT_PATH=$name" >> ~/.shellnotes/sne/.env
echo "Default notes folder updated."
echo "Please restart your terminal."
fi

0
sne/.env Normal file
View file

29
sne/gist.py Normal file
View file

@ -0,0 +1,29 @@
import os
import sys
import json
import datetime
import requests
def create_gist_with_requests(headers, body):
response = requests.post('https://api.github.com/gists', json=body, headers=headers)
if response.ok:
response_data = response.json()
return response_data["html_url"]
else:
raise RuntimeError(f"Github API error: {response.status_code}")
def create_gist(text, token):
today = datetime.date.today()
headers = {
'Authorization': f'Bearer {token}',
'User-agent': 'python-gist',
'Accept': 'application/json',
'X-GitHub-Api-Version': '2022-11-28'
}
body = {
"description": f"Uploaded on {today} via SnE",
"files": {f"{today}.txt": {"content": text}},
"public": False
}
return create_gist_with_requests(headers, body)

14
sne/pastebin.py Normal file
View file

@ -0,0 +1,14 @@
import requests
def pastebin(text):
api_key = "d2004f9b24624585334cc3950ab6a7e0"
url = "https://pastebin.com/api/api_post.php"
payload = {
"api_dev_key": api_key,
"api_paste_code": text,
"api_paste_private": 0,
"api_option": "paste"
}
res = requests.post(url, data=payload)
return (res.text)

17
sne/requirements.txt Normal file
View file

@ -0,0 +1,17 @@
astroid==2.3.3
isort==4.3.21
lazy-object-proxy==1.4.3
mccabe==0.6.1
Pillow==7.0.0
pycodestyle==2.5.0
pyenchant==2.0.0
Pygments==2.5.2
pylint==2.4.4
pyttsx3==2.71
six==1.13.0
ttkthemes==2.4.0
typed-ast==1.4.0
wrapt==1.11.2
python-dotenv==1.0.0
loguru==0.7.0

612
sne/sne.py Normal file
View file

@ -0,0 +1,612 @@
"""
SnE - Shellnotes Notes Editor
Developed by Dimitris Marakomichelakis
"""
import tkinter as tk
from tkinter import ttk
from tkinter import *
from functools import partial
from tkinter import messagebox
from tkinter import filedialog
from tkinter import simpledialog
import tkinter.font as tkFont
from pathlib import Path
import sys
import os
import time
import pyttsx3
import enchant
from ttkthemes import ThemedTk
import pastebin
from dotenv import load_dotenv
from gist import create_gist
from loguru import logger
load_dotenv() #.env must contain the GH_TOKEN variable, set via shellnotes --set-github-token
default_path = os.environ.get("DEFAULT_PATH")
def _log(level, message):
log_dir = os.path.expanduser("~/.shellnotes/logs/sne") # Use a valid path for the log directory
os.makedirs(log_dir, exist_ok=True) # Create the directory if it doesn't exist
log_path = os.path.join(log_dir, f"logfile_{time}.log")
logger.add(log_path)
# print(log_path)
if level == "TRACE":
logger.trace(message)
elif level == "DEBUG":
logger.debug(message)
elif level == "INFO":
logger.info(message)
elif level == "SUCCESS":
logger.success(message)
elif level == "WARNING":
logger.warning(message)
elif level == "ERROR":
logger.error(message)
elif level == "CRITICAL":
logger.info(message)
else:
return "Failed to log"
class Container(Text):
"""
A TextWidget with horizontal and vertical scrollbars
"""
def __init__(self, master=None, **kw):
self.frame = ttk.Frame(master)
self.vbar = ttk.Scrollbar(self.frame, command=self.yview)
self.vbar.pack(side=RIGHT, fill=Y)
self.hbar = ttk.Scrollbar(
self.frame, orient="horizontal", command=self.xview)
self.hbar.pack(side=BOTTOM, fill=X)
kw.update({'yscrollcommand': self.vbar.set})
kw.update({'xscrollcommand': self.hbar.set})
Text.__init__(self, self.frame, **kw)
self.pack(side=LEFT, fill=BOTH, expand=True)
text_meths = vars(Text).keys()
methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys()
methods = methods.difference(text_meths)
for m in methods:
if m[0] != '_' and m != 'config' and m != 'configure':
setattr(self, m, getattr(self.frame, m))
def __str__(self):
return str(self.frame)
class Editor:
"""
Base Class of Editor
"""
window = ThemedTk()
style = ttk.Style()
window.title("SnE")
# window.geometry(
# "{0}x{1}+0+0".format(window.winfo_screenwidth(),
# window.winfo_screenheight()))
window.geometry("500x500")
menuBar = Menu(window)
#The text and entry frames column
window.grid_columnconfigure(1, weight=1)
window.grid_rowconfigure(0, weight=1)
#Menu bar
window.config(menu=menuBar)
fileMenu = Menu(menuBar, tearoff=0)
editMenu = Menu(menuBar, tearoff=0)
viewMenu = Menu(menuBar, tearoff=0)
toolMenu = Menu(menuBar, tearoff=0)
helpMenu = Menu(menuBar, tearoff=0)
txt = Container(window, undo=True)
txt.grid(row=0, column=1, sticky="NSEW")
lineNumber = Canvas(window, width="30", height="500")
lineNumber.grid(row=0, column=0, sticky='NS', pady=1, rowspan=3)
charCount = StringVar()
charCount.set("Characters: 0")
statusBar = ttk.Label(window, textvariable=charCount)
statusBar.grid(row=2, column=1, columnspan=2, sticky="EW")
txt['wrap'] = 'none'
fontType = "Helvetica"
fontSize = "15"
fontColor = "black"
fontWeight = "normal"
txt.configure(font=(fontType, fontSize, fontWeight))
currentFile = "No File"
def __init__(self):
# Disable default bindings for Ctrl+C and Ctrl+V
self.txt.unbind("<Control-c>")
self.txt.unbind("<Control-v>")
self.fileMenu.add_command(
label="New", command=self.new_file, accelerator="Ctrl+N")
self.window.bind_all('<Control-n>', self.new_file)
# self.fileMenu.add_command(
# label="Open", command=self.open_file, accelerator="Ctrl+O")
# self.window.bind_all('<Control-o>', self.open_file)
self.fileMenu.add_command(
label="Save", command=self.save_file, accelerator="Ctrl+S")
self.window.bind_all('<Control-s>', self.save_file)
self.fileMenu.add_command(
label="Save As", command=self.save_file_as,
accelerator="Ctrl+Shift+S")
self.window.bind_all('<Control-S>', self.save_file_as)
self.fileMenu.add_command(label="Exit", command=self.exit)
self.menuBar.add_cascade(label="File", menu=self.fileMenu)
self.editMenu = Menu(self.menuBar, tearoff=0)
self.editMenu.add_command(label="Cut", command=self.cut)
self.editMenu.add_command(
label="Copy", command=self.copy, accelerator="Ctrl+C")
self.window.bind_all('<Control-c>', self.copy)
self.editMenu.add_command(
label="Paste", command=self.paste, accelerator="Ctrl+V")
self.window.bind_all('<Control-v>', self.paste)
self.editMenu.add_command(
label="Undo", command=self.undo, accelerator="Ctrl+Z")
self.window.bind_all('<Control-z>', self.undo)
self.editMenu.add_command(
label="Redo", command=self.redo, accelerator="Ctrl+R")
self.window.bind_all('<Control-r>', self.redo)
self.toolMenu = Menu(self.menuBar, tearoff=0)
self.toolMenu.add_command(
label="Find", command=self.find, accelerator="Ctrl+F")
self.window.bind_all('<Control-f>', self.find)
self.toolMenu.add_command(
label="Replace All...", command=self.replace,
accelerator="Ctrl+Shift+R")
self.window.bind_all('<Control-R>', self.replace)
self.toolMenu.add_command(
label="Paste on Pastebin", command=self.paste_on)
self.toolMenu.add_command(
label="Paste on Github Gists", command=self.gist)
self.toolMenu.add_command(label="Read Aloud", command=self.speak)
self.toolMenu.add_command(
label="Spell Check", command=self.spell_check)
self.menuBar.add_cascade(label="Edit", menu=self.editMenu)
self.menuBar.add_cascade(label="View", menu=self.viewMenu)
self.menuBar.add_cascade(label="Tools", menu=self.toolMenu)
self.helpMenu.add_command(label="About", command=self.about)
self.menuBar.add_cascade(label="Help", menu=self.helpMenu)
self.window.bind_all('<Return>', self.redraw)
self.window.bind_all('<BackSpace>', self.redraw)
self.window.bind_all('<Key>', self.redraw)
self.window.bind_all('<Button-4>', self.redraw)
self.window.bind_all('<Button-5>', self.redraw)
self.window.bind_all('<Configure>', self.redraw)
self.window.bind_all('<Motion>', self.redraw)
self.editMenu.add_command(
label="Select All", command=self.selectall, accelerator="Ctrl+A")
self.window.bind_all('<Control-a>', self.selectall)
fontFamily = Menu(self.viewMenu)
fontFamily.add_command(label="Helvetica (Default)", command=partial(
self.change_font_family, "Helvetica"))
fontFamily.add_command(label="Ubuntu", command=partial(
self.change_font_family, "Ubuntu"))
fontFamily.add_command(label="Times New Roman", command=partial(
self.change_font_family, "Times New Roman"))
fontFamily.add_command(label="Comic Sans MS", command=partial(
self.change_font_family, "Comic Sans MS"))
fontFamily.add_command(label="Terminal", command=partial(
self.change_font_family, "Terminal"))
self.viewMenu.add_cascade(label="Font Family", menu=fontFamily)
self.viewMenu.add_command(label="Font Size", command=self.change_font_size)
# self.viewMenu.add_command(label="Font Weight", command=self.change_font_weight)
fontWeightMenu = Menu(self.viewMenu)
fontWeightMenu.add_command(label="Normal", command=lambda: self.change_font_weight("normal"))
fontWeightMenu.add_command(label="Bold", command=lambda: self.change_font_weight("bold"))
self.viewMenu.add_cascade(label="Font Weight", menu=fontWeightMenu)
themeBar = Menu(self.viewMenu)
themeBar.add_command(label="Black", command=partial(
self.change_theme, "black"))
themeBar.add_command(label="White", command=partial(
self.change_theme, "white"))
themeBar.add_command(label="Aqua", command=partial(
self.change_theme, "aqua"))
themeBar.add_command(label="Matrix", command=partial(
self.change_theme, "matrix"))
themeBar.add_command(label="SnE Original", command=partial(
self.change_theme, "sne"))
self.viewMenu.add_cascade(label="Themes", menu=themeBar)
if len(sys.argv) > 1:
self.open_specific_file(f"{default_path}/{sys.argv[1]}") # Open the specified file
self.window.mainloop()
def new_file(self, event=None):
if(messagebox.askyesno("Save?", "Do you wish to save current file?")):
self.save_file()
self.txt.delete('1.0', END)
self.window.title("SnE - New File")
self.currentFile = "No File"
else:
self.txt.delete('1.0', END)
self.window.title("SnE")
self.currentFile = "No File"
def open_file(self, event=None):
# print("Opening file")
myFile = filedialog.askopenfile(
parent=self.window, mode="rb", title="Open a Note")
if myFile is not None:
self.window.title(os.path.basename(myFile.name))
content = myFile.read()
self.txt.delete('1.0', END)
self.txt.insert(1.0, content)
self.currentFile = myFile.name
_log("SUCCESS", f"Opened Note {self.currentFile}")
myFile.close()
self.redraw(event)
else:
_log("ERROR", f"Note filename is empty ({self.currentFile=})")
def open_specific_file(self, file_path):
try:
with open(file_path, "rb") as myFile:
self.window.title(os.path.basename(myFile.name))
content = myFile.read()
self.txt.delete('1.0', END)
self.txt.insert(1.0, content)
self.currentFile = myFile.name
_log("SUCCESS", f"Opened Note {self.currentFile}")
self.redraw(event)
except Exception as e:
_log("ERROR", f"Failed to open (specific) file: {str(e)}")
# def save_file_as(self, event=None):
# # print("Saving file")
# myFile = filedialog.asksaveasfile(mode="w")
# if myFile is not None:
# myFile.write(self.txt.get('1.0', END))
# self.currentFile = myFile.name
# _log("SUCCESS", f"Saved New Note {self.currentFile}")
# myFile.close()
# self.window.title(os.path.basename(myFile.name))
def save_file_as(self, event=None):
try:
# Read initial_directory from sd-input3.txt
with open(os.path.expanduser("~/.shellnotes/util/shellnotes/sd/sd-input3.txt")) as f:
initial_directory = f.read().strip()
# Prompt the user for a file name
file_name = simpledialog.askstring("Save As", "Enter a file name:")
if not file_name:
_log("ERROR", f"No note name specified ({file_name=})")
return
# Construct the full file path using initial_directory and file_name
full_directory = os.path.expanduser(initial_directory)
file_path = os.path.join(full_directory, file_name)
# Open and write to the file
with open(file_path, "w+") as myFile:
myFile.write(self.txt.get('1.0', END))
self.currentFile = file_path
_log("SUCCESS", f"Saved New Note {self.currentFile}")
self.window.title(os.path.basename(self.currentFile))
except Exception as e:
# Handle any errors that might occur while saving
_log("ERROR", f"Failed to save: {str(e)}")
def save_file(self, event=None):
# print(self.currentFile)
if (self.currentFile == "No File"):
self.save_file_as(event)
else:
myFile = open(self.currentFile, "w")
myFile.write(self.txt.get('1.0', END))
_log("SUCCESS", f"Saved Note {self.currentFile}")
myFile.close()
def copy(self, event=None):
# print("copying")
self.txt.clipboard_clear()
self.txt.clipboard_append(self.txt.selection_get())
_log("INFO", f"Copied: {self.txt.selection_get()}")
def cut(self, event=None):
self.copy()
self.txt.delete(SEL_FIRST, SEL_LAST)
def paste(self, event=None):
try:
# Delete the selected text, if any
sel_start = self.txt.index("sel.first")
sel_end = self.txt.index("sel.last")
if sel_start and sel_end:
self.txt.delete(sel_start, sel_end)
# Paste the clipboard content at the cursor position
self.txt.insert(INSERT, self.txt.clipboard_get())
self.redraw(event)
except:
pass
def undo(self, event=None):
self.txt.edit_undo()
def redo(self, event=None):
self.txt.edit_redo()
def find(self, event=None):
root = Toplevel(self.window)
root.title("notegrep")
root.transient(self.window)
root.focus_force()
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
e1 = ttk.Entry(root)
e1.grid(row=0, column=0, pady="10",
padx="10", columnspan=2, sticky="EW")
def sub():
findString = e1.get()
self.set_mark(findString)
def on_closing():
self.txt.tag_delete('highlight')
root.destroy()
findBtn = ttk.Button(root, text="Find...", command=sub)
findBtn.grid(row=1, column=0, pady="10", padx="10", sticky="EWS")
closeBtn = ttk.Button(root, text="Close", command=on_closing)
closeBtn.grid(row=1, column=1, pady="10", padx="10", sticky="EWS")
root.protocol("WM_DELETE_WINDOW", on_closing)
def paste_on(self, event=None):
def copy_link(self, link):
self.txt.clipboard_clear()
self.txt.clipboard_append(link)
root = Toplevel(self.window)
root.title("PasteBin Link")
root.transient(self.window)
root.focus_force()
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
link = pastebin.pastebin(self.txt.get('1.0', END))
_log("SUCCESS", f"Uploaded Note to pastebin ({link})")
lb = ttk.Label(root, text=link)
lb.grid(row=0, column=0, padx="50", pady="20")
bt = ttk.Button(root, text="Copy", command=copy_link(self, link))
bt.grid(row=1, column=0, padx="50", pady="20")
def gist(self, event=None):
def copy_link(link):
self.txt.clipboard_clear()
self.txt.clipboard_append(link)
try:
text = self.txt.get('1.0', END)
token = os.getenv("GH_TOKEN")
if not token:
messagebox.showerror("Error", "GH_TOKEN not set. You can set it using the shellnotes --set-github-token")
_log("ERROR", "No github token.")
except:
raise RuntimeError("GH_TOKEN not set")
try:
link = create_gist(text, token)
_log("SUCCESS", f"Uploaded Note to Github Gists ({link})")
root = Toplevel(self.window)
root.title("Github Gists Link")
root.transient(self.window)
root.focus_force()
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
lb = ttk.Label(root, text=link)
lb.grid(row=0, column=0, padx="50", pady="20")
bt = ttk.Button(root, text="Copy", command=lambda: copy_link(link))
bt.grid(row=1, column=0, padx="50", pady="20")
except Exception as e:
messagebox.showerror("Error", str(e))
_log("ERROR", f"Couldn't upload to Github Gists ({str(e)})")
def selectall(self, event=None):
self.txt.tag_add('sel', '1.0', 'end')
return "break"
def set_mark(self, findString):
print("Coming to set mark")
self.find_string(findString)
self.txt.tag_config('highlight', foreground='red')
self.txt.focus_force()
def find_string(self, findString):
startInd = '1.0'
while(startInd):
startInd = self.txt.search(findString, startInd, stopindex=END)
if startInd:
startInd = str(startInd)
lastInd = startInd+f'+{len(findString)}c'
print(startInd, lastInd)
self.txt.tag_add('highlight', startInd, lastInd)
startInd = lastInd
def replace(self, event=None):
# print("About to replace using notegrep")
root = Toplevel(self.window)
root.title("Find and Replace")
root.transient(self.window)
root.focus_force()
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
e1 = ttk.Entry(root)
e1.grid(row=0, column=0, pady=5, columnspan=2, padx=10)
e2 = ttk.Entry(root)
e2.grid(row=1, column=0, pady=5, columnspan=2, padx=10)
def find():
findString = e1.get()
self.set_mark(findString)
def replace():
findString = e1.get()
replaceString = e2.get()
myText = self.txt.get('1.0', END)
myText = myText.replace(findString, replaceString)
self.txt.delete('1.0', END)
self.txt.insert('1.0', myText)
root.destroy()
def on_closing():
self.txt.tag_delete('highlight')
root.destroy()
findButton = ttk.Button(root, text="Find", command=find)
replaceButton = ttk.Button(root, text="Replace", command=replace)
findButton.grid(row=2, column=0, padx=10, pady=5)
replaceButton.grid(row=2, column=1, padx=10, pady=5)
root.protocol("WM_DELETE_WINDOW", on_closing)
def redraw(self, event=NONE):
self.update_count(event)
self.lineNumber.delete("all")
self.objectIds = []
si = self.txt.index("@0,0")
while True:
dline = self.txt.dlineinfo(si)
if dline is None:
break
y = dline[1]
liNum = str(si).split(".")[0]
self.lineNumber.create_text(
2, y, anchor="nw", text=liNum, fill=self.fontColor)
si = self.txt.index(f"{si}+1line")
def update_count(self, event):
count = self.txt.get('1.0', END)
self.charCount.set(f"Characters: {len(count)-1}")
def speak(self):
"""Read selected text aloud. Reads the whole note if nothing is selected."""
engine = pyttsx3.init()
try:
selected_text = self.txt.selection_get()
engine.say(selected_text)
except tk.TclError:
# If no text is selected, read the entire content of the text widget
engine.say(self.txt.get("1.0", END))
engine.runAndWait()
def spell_err(self, findString):
"""Check for Spelling Errors"""
startInd = '1.0'
while True:
startInd = self.txt.search(findString, startInd, stopindex=END, nocase=True)
if not startInd:
break
endInd = f"{startInd}+{len(findString)}c"
self.txt.tag_add('misspelled', startInd, endInd)
startInd = endInd
def spell_check(self, event=NONE):
print("Running Spell check")
self.txt.tag_delete('misspelled')
words = set(self.txt.get('1.0', "end-1c").split()) # Use a set to store unique words
for word in words:
if not self.word_exist(word):
self.spell_err(word)
self.txt.tag_config('misspelled', background="red", foreground="white")
def word_exist(self, word):
d = enchant.Dict("en_US")
return d.check(word)
def change_theme(self, theme):
if (theme == "black"):
self.fontColor = "white"
self.window['theme'] = 'black'
self.txt.config(bg="black", fg="white", insertbackground="white")
self.txt['fg'] = 'white'
self.lineNumber.config(bg="black")
self.menuBar.config(bg="black", fg="white")
pass
elif (theme == "white"):
self.fontColor = "black"
self.window['theme'] = 'aquativo'
self.lineNumber.config(bg="white")
self.txt.config(bg="white", fg="black", insertbackground="black")
self.menuBar.config(bg="white", fg="black")
pass
elif (theme == "matrix"):
self.fontColor = "black"
self.window['theme'] = 'black'
self.lineNumber.config(bg="green")
self.txt.config(bg="black", fg="green", insertbackground="white")
self.menuBar.config(bg="green", fg="black", relief=RAISED)
elif (theme == "aqua"):
self.fontColor = "green"
self.window['theme'] = 'arc'
self.lineNumber.config(bg="#9de1fd")
self.txt.config(bg="white", fg="black", insertbackground="black")
self.menuBar.config(bg="#9de1fd", fg="black", relief=RAISED)
elif (theme == "sne"):
self.fontColor = "black"
self.window['theme'] = 'kroc'
self.lineNumber.config(bg="#eaddca")
self.txt.config(bg="#997950", fg="black", insertbackground="black")
self.menuBar.config(bg="black", fg="#eaddca", relief=RAISED)
def change_font_size(self):
"""Adjust Font Size"""
new_font_size = simpledialog.askstring(
"Size", "Enter font size", parent=self.window)
if new_font_size is not None:
self.fontSize = new_font_size
self.update_font()
def change_font_family(self, fontType):
"""Change Font Family"""
self.fontType = fontType
self.update_font()
def change_font_weight(self, fontWeight):
"""Adjust Font Weight"""
self.fontWeight = fontWeight
self.update_font()
def update_font(self):
self.txt.configure(font=(self.fontType, self.fontSize, self.fontWeight))
def about(self):
# print("Showing About Page")
messagebox.showinfo("Shellnotes Note Editor (SNE)", "An editor used for viewing and editing your notes.\nVersion: 1.0")
def exit(self):
if(messagebox.askyesno('Quit', 'Are you sure you want to quit?')):
self.window.destroy()
a = Editor()

View file

@ -10,16 +10,18 @@ function resetshellnotes() {
proceed() {
echo "y\n" | clearlogs >/dev/null
echo "" > ~/.shellnotes/util/listnotes/output/*
echo "/usr/bin/gedit" > ~/.shellnotes/util/shellnotes/sd/sd-input1.txt
echo ".shellnotes/sne/sne.py" > ~/.shellnotes/util/shellnotes/sd/sd-input1.txt
echo "/bin/nano"> ~/.shellnotes/util/shellnotes/sd/sd-input2.txt
echo "~/Notes" > ~/.shellnotes/util/shellnotes/sd/sd-input3.txt
reset="
#The first line is the user's default shell found during installation process.
#Warning! If you don't have gedit(text editor) or nano installed, you may have to change the default text editor (lines 10, 25, 40).
#The lines below must NOT be changed.
export DIR="$(pwd)"
.~/.shellnotes/whatsnew.sh
. ~/.shellnotes/util/getv.sh
. ~/.shellnotes/def/defaults.sh
. ~/.shellnotes/util/ChMkDir.sh
@ -34,6 +36,8 @@ export DIR="$(pwd)"
. ~/.shellnotes/util/renamenote.sh
. ~/.shellnotes/util/notewc.sh
. ~/.shellnotes/util/notegrep.sh
. ~/.shellnotes/util/clipnote.sh
. ~/.shellnotes/util/rmdups.sh
@ -44,6 +48,9 @@ export DIR="$(pwd)"
"
echo $reset > ~/.shellnotes/.shellnotes.sh
# mv ~/.shellnotes/.shellnotes.sh ~/.shellnotes/shellnotes.sh
rm -rf ~/.shellnotes/**/__pycache__
echo "" > ~/.shellnotes/**/.env
}
case $1 in -f | --force )
@ -53,7 +60,7 @@ export DIR="$(pwd)"
esac
echo "Be aware that this command will erase shellnotes' memory."
echo "This contains default editors and folder, logfiles and user data and cache."
echo "This contains default editors and folder, logfiles, user data and cache."
echo "Your Notes will not be removed."
echo -n "Proceed? " && read input
case $input in y|Yes|Y|YES|yes)

View file

@ -14,6 +14,7 @@ function shellnotes() {
. ~/.shellnotes/util/shellnotes/au/au.sh
. ~/.shellnotes/util/shellnotes/sd/sd.sh
. ~/.shellnotes/util/shellnotes/i/i.sh
. ~/.shellnotes/util/shellnotes/gh_token/gh_token.sh
if [[ $# > 1 ]]; then
echo "Too many arguments."
elif [[ $# = 0 ]];then

View file

@ -1 +1 @@
/usr/bin/gedit
.shellnotes/sne/sne.py