kopipasta 0.17.0__py3-none-any.whl → 0.19.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
kopipasta/main.py CHANGED
@@ -5,14 +5,27 @@ import json
5
5
  import os
6
6
  import argparse
7
7
  import re
8
+ import subprocess
9
+ import tempfile
8
10
  from typing import Dict, List, Optional, Set, Tuple
9
11
  import pyperclip
10
12
  import fnmatch
13
+ from pygments import highlight
14
+ from pygments.lexers import get_lexer_for_filename, TextLexer
15
+ from pygments.formatters import TerminalFormatter
16
+ import pygments.util
11
17
 
12
18
  import requests
13
19
 
14
20
  FileTuple = Tuple[str, bool, Optional[List[str]], str]
15
21
 
22
+ def get_colored_code(file_path, code):
23
+ try:
24
+ lexer = get_lexer_for_filename(file_path)
25
+ except pygments.util.ClassNotFound:
26
+ lexer = TextLexer()
27
+ return highlight(code, lexer, TerminalFormatter())
28
+
16
29
  def read_gitignore():
17
30
  default_ignore_patterns = [
18
31
  '.git', 'node_modules', 'venv', '.venv', 'dist', '.idea', '__pycache__',
@@ -375,7 +388,8 @@ def select_file_patches(file_path):
375
388
  print(f"\nSelecting patches for {file_path}")
376
389
  for index, (chunk_code, start_line, end_line) in enumerate(code_chunks):
377
390
  print(f"\nChunk {index + 1} (Lines {start_line + 1}-{end_line}):")
378
- print(f"```{language}\n{chunk_code}\n```")
391
+ colored_chunk = get_colored_code(file_path, chunk_code)
392
+ print(colored_chunk)
379
393
  while True:
380
394
  choice = input("(y)es include / (n)o skip / (q)uit rest of file? ").lower()
381
395
  if choice == 'y':
@@ -422,6 +436,10 @@ def get_file_snippet(file_path, max_lines=50, max_bytes=4096):
422
436
  byte_count += len(line.encode('utf-8'))
423
437
  return snippet
424
438
 
439
+ def get_colored_file_snippet(file_path, max_lines=50, max_bytes=4096):
440
+ snippet = get_file_snippet(file_path, max_lines, max_bytes)
441
+ return get_colored_code(file_path, snippet)
442
+
425
443
  def print_char_count(count):
426
444
  token_estimate = count // 4
427
445
  print(f"\rCurrent prompt size: {count} characters (~ {token_estimate} tokens)", flush=True)
@@ -671,7 +689,7 @@ def handle_env_variables(content, env_vars):
671
689
 
672
690
  return content
673
691
 
674
- def generate_prompt(files_to_include: List[FileTuple], ignore_patterns: List[str], web_contents: Dict[str, Tuple[FileTuple, str]], env_vars: Dict[str, str]) -> str:
692
+ def generate_prompt_template(files_to_include: List[FileTuple], ignore_patterns: List[str], web_contents: Dict[str, Tuple[FileTuple, str]], env_vars: Dict[str, str]) -> Tuple[str, int]:
675
693
  prompt = "# Project Overview\n\n"
676
694
  prompt += "## Project Structure\n\n"
677
695
  prompt += "```\n"
@@ -704,8 +722,8 @@ def generate_prompt(files_to_include: List[FileTuple], ignore_patterns: List[str
704
722
  prompt += f"### {url}{' (snippet)' if is_snippet else ''}\n\n```{language}\n{content}\n```\n\n"
705
723
 
706
724
  prompt += "## Task Instructions\n\n"
707
- task_instructions = input("Enter the task instructions: ")
708
- prompt += f"{task_instructions}\n\n"
725
+ cursor_position = len(prompt)
726
+ prompt += "\n\n"
709
727
  prompt += "## Instructions for Achieving the Task\n\n"
710
728
  analysis_text = (
711
729
  "1. **Confirm and Understand the Task**:\n"
@@ -733,12 +751,38 @@ def generate_prompt(files_to_include: List[FileTuple], ignore_patterns: List[str
733
751
  " - Request the user to share any error messages or outputs from debugging to assist further.\n"
734
752
  )
735
753
  prompt += analysis_text
736
- return prompt
754
+ return prompt, cursor_position
755
+
756
+ def open_editor_for_input(template: str, cursor_position: int) -> str:
757
+ editor = os.environ.get('EDITOR', 'vim')
758
+ with tempfile.NamedTemporaryFile(mode='w+', suffix='.md', delete=False) as temp_file:
759
+ temp_file.write(template)
760
+ temp_file.flush()
761
+ temp_file_path = temp_file.name
762
+
763
+ try:
764
+ cursor_line = template[:cursor_position].count('\n') + 1
765
+ cursor_column = cursor_position - template.rfind('\n', 0, cursor_position)
766
+
767
+ if 'vim' in editor or 'nvim' in editor:
768
+ subprocess.call([editor, f'+call cursor({cursor_line}, {cursor_column})', '+startinsert', temp_file_path])
769
+ elif 'emacs' in editor:
770
+ subprocess.call([editor, f'+{cursor_line}:{cursor_column}', temp_file_path])
771
+ elif 'nano' in editor:
772
+ subprocess.call([editor, f'+{cursor_line},{cursor_column}', temp_file_path])
773
+ else:
774
+ subprocess.call([editor, temp_file_path])
737
775
 
776
+ with open(temp_file_path, 'r') as file:
777
+ content = file.read()
778
+ return content
779
+ finally:
780
+ os.unlink(temp_file_path)
738
781
 
739
782
  def main():
740
783
  parser = argparse.ArgumentParser(description="Generate a prompt with project structure, file contents, and web content.")
741
784
  parser.add_argument('inputs', nargs='+', help='Files, directories, or URLs to include in the prompt')
785
+ parser.add_argument('-t', '--task', help='Task description for the AI prompt')
742
786
  args = parser.parse_args()
743
787
 
744
788
  ignore_patterns = read_gitignore()
@@ -791,7 +835,9 @@ def main():
791
835
  use_snippet = is_large_file(input_path)
792
836
  files_to_include.append((input_path, use_snippet, None, get_language_for_file(input_path)))
793
837
  if use_snippet:
794
- current_char_count += len(get_file_snippet(input_path))
838
+ snippet = get_file_snippet(input_path)
839
+ current_char_count += len(snippet)
840
+ print(get_colored_code(input_path, snippet))
795
841
  else:
796
842
  current_char_count += os.path.getsize(input_path)
797
843
  print(f"Added file: {input_path}{' (snippet)' if use_snippet else ''}")
@@ -826,16 +872,23 @@ def main():
826
872
  print_char_count(current_char_count)
827
873
  print(f"Summary: Added {len(files_to_include)} files from {len(processed_dirs)} directories and {len(web_contents)} web sources.")
828
874
 
829
- prompt = generate_prompt(files_to_include, ignore_patterns, web_contents, env_vars)
875
+ prompt_template, cursor_position = generate_prompt_template(files_to_include, ignore_patterns, web_contents, env_vars)
876
+
877
+ if args.task:
878
+ task_description = args.task
879
+ final_prompt = prompt_template[:cursor_position] + task_description + prompt_template[cursor_position:]
880
+ else:
881
+ final_prompt = open_editor_for_input(prompt_template, cursor_position)
882
+
830
883
  print("\n\nGenerated prompt:")
831
- print(prompt)
884
+ print(final_prompt)
832
885
 
833
886
  # Copy the prompt to clipboard
834
887
  try:
835
- pyperclip.copy(prompt)
888
+ pyperclip.copy(final_prompt)
836
889
  separator = "\n" + "=" * 40 + "\n☕🍝 Kopipasta Complete! 🍝☕\n" + "=" * 40 + "\n"
837
890
  print(separator)
838
- final_char_count = len(prompt)
891
+ final_char_count = len(final_prompt)
839
892
  final_token_estimate = final_char_count // 4
840
893
  print(f"Prompt has been copied to clipboard. Final size: {final_char_count} characters (~ {final_token_estimate} tokens)")
841
894
  except pyperclip.PyperclipException as e:
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.1
2
+ Name: kopipasta
3
+ Version: 0.19.0
4
+ Summary: A CLI tool to generate prompts with project structure and file contents
5
+ Home-page: https://github.com/mkorpela/kopipasta
6
+ Author: Mikko Korpela
7
+ Author-email: mikko.korpela@gmail.com
8
+ License: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: pyperclip==1.9.0
23
+ Requires-Dist: requests==2.32.3
24
+
25
+ # kopipasta
26
+
27
+ [![Version](https://img.shields.io/pypi/v/kopipasta.svg)](https://pypi.python.org/pypi/kopipasta)
28
+ [![Downloads](http://pepy.tech/badge/kopipasta)](http://pepy.tech/project/kopipasta)
29
+
30
+ A CLI tool for generating AI-assisted code prompts with project structure and file contents, using an interactive editor-based workflow.
31
+
32
+ <img src="kopipasta.jpg" alt="kopipasta" width="300">
33
+
34
+ - An LLM told me that kopi means Coffee in some languages.. and a Diffusion model then made this delicious soup.
35
+
36
+ ## Installation
37
+
38
+ You can install kopipasta using pipx (or pip):
39
+
40
+ ```bash
41
+ pipx install kopipasta
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ To use kopipasta, run the following command in your terminal:
47
+
48
+ ```bash
49
+ kopipasta [files_or_directories_or_urls]
50
+ ```
51
+
52
+ Replace `[files_or_directories_or_urls]` with the paths to the files or directories you want to include in the prompt, as well as any web URLs you want to fetch content from.
53
+
54
+ Example:
55
+ ```bash
56
+ kopipasta src/ config.json https://example.com/api-docs
57
+ ```
58
+
59
+ This will guide you through an interactive process to:
60
+ 1. Select files and directories to include in the prompt
61
+ 2. Choose between full content, snippets, or patches for large files
62
+ 3. Fetch and include content from provided URLs
63
+ 4. Open an editor for you to input the specific task or code generation instructions
64
+ 5. Generate a comprehensive prompt that includes project structure, selected file contents, and your task instructions
65
+
66
+ The generated prompt will be displayed in the console and automatically copied to your clipboard, ready to be used with an AI code generation tool.
67
+
68
+ ## Features
69
+
70
+ - Generates structured prompts with project overview, file contents, web content, and task instructions
71
+ - Interactive file selection process with options for full content, snippets, or specific patches
72
+ - Fetches and includes content from web URLs
73
+ - Opens your preferred editor (configurable via EDITOR environment variable) for task input
74
+ - Detects and securely handles environment variables from a `.env` file
75
+ - Ignores files and directories based on common .gitignore patterns
76
+ - Allows interactive selection of files to include
77
+ - Supports various file types with syntax highlighting in the selection process
78
+ - Automatically copies the generated prompt to the clipboard
@@ -0,0 +1,8 @@
1
+ kopipasta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ kopipasta/main.py,sha256=zHCgL8dIZ4qMDzaN4EgUltH7wRT8UVvLn0Fq5ZgEZ8s,36904
3
+ kopipasta-0.19.0.dist-info/LICENSE,sha256=xw4C9TAU7LFu4r_MwSbky90uzkzNtRwAo3c51IWR8lk,1091
4
+ kopipasta-0.19.0.dist-info/METADATA,sha256=ipQ4jhKhnSgb2YKffbZZdBcx7FBZYodmS_g95Dx3aAY,3147
5
+ kopipasta-0.19.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
6
+ kopipasta-0.19.0.dist-info/entry_points.txt,sha256=but54qDNz1-F8fVvGstq_QID5tHjczP7bO7rWLFkc6Y,50
7
+ kopipasta-0.19.0.dist-info/top_level.txt,sha256=iXohixMuCdw8UjGDUp0ouICLYBDrx207sgZIJ9lxn0o,10
8
+ kopipasta-0.19.0.dist-info/RECORD,,
@@ -1,200 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: kopipasta
3
- Version: 0.17.0
4
- Summary: A CLI tool to generate prompts with project structure and file contents
5
- Home-page: https://github.com/mkorpela/kopipasta
6
- Author: Mikko Korpela
7
- Author-email: mikko.korpela@gmail.com
8
- License: MIT
9
- Classifier: Development Status :: 3 - Alpha
10
- Classifier: Intended Audience :: Developers
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Operating System :: OS Independent
13
- Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.8
15
- Classifier: Programming Language :: Python :: 3.9
16
- Classifier: Programming Language :: Python :: 3.10
17
- Classifier: Programming Language :: Python :: 3.11
18
- Classifier: Programming Language :: Python :: 3.12
19
- Requires-Python: >=3.8
20
- Description-Content-Type: text/markdown
21
- License-File: LICENSE
22
- Requires-Dist: pyperclip==1.9.0
23
- Requires-Dist: requests==2.32.3
24
-
25
- # kopipasta
26
-
27
- A CLI tool to generate prompts with project structure, file contents, and web content, while handling environment variables securely and offering snippets for large files also interactive patch selection, allowing you to include only the most relevant parts of your code.
28
-
29
- <img src="kopipasta.jpg" alt="kopipasta" width="300">
30
-
31
- - An LLM told me that kopi means Coffee in some languages.. and a Diffusion model then made this delicious soup.
32
-
33
- ## Installation
34
-
35
- You can install kopipasta using pipx (or pip):
36
-
37
- ```
38
- pipx install kopipasta
39
- ```
40
-
41
- ## Usage
42
-
43
- To use kopipasta, run the following command in your terminal:
44
-
45
- ```
46
- kopipasta [files_or_directories_or_urls]
47
- ```
48
-
49
- Replace `[files_or_directories_or_urls]` with the paths to the files or directories you want to include in the prompt, as well as any web URLs you want to fetch content from.
50
-
51
- Example:
52
- ```
53
- kopipasta src/ config.json https://example.com/api-docs
54
- ```
55
-
56
- This will generate a prompt including:
57
- - The project structure
58
- - Contents of the specified files and directories (with snippet options for large files)
59
- - Content fetched from the provided URLs (with snippet options for large content)
60
- - Handling of environment variables found in a `.env` file (if present)
61
-
62
- Files and directories typically excluded in version control (based on common .gitignore patterns) are ignored.
63
-
64
- The generated prompt will be displayed in the console and automatically copied to your clipboard.
65
-
66
- ## Features
67
-
68
- - Generates a structured prompt with project overview, file contents, web content, and task instructions
69
- - Offers snippet options for large files (>100 KB) and web content (>10,000 characters)
70
- - Fetches and includes content from web URLs
71
- - Detects and securely handles environment variables from a `.env` file
72
- - Ignores files and directories based on common .gitignore patterns
73
- - Allows interactive selection of files to include
74
- - Automatically copies the generated prompt to the clipboard
75
-
76
- ## Environment Variable Handling
77
-
78
- If a `.env` file is present in the current directory, kopipasta will:
79
- 1. Read and store the environment variables
80
- 2. Detect these variables in file contents and web content
81
- 3. Prompt you to choose how to handle each detected variable:
82
- - (m)ask: Replace the value with asterisks
83
- - (s)kip: Replace the value with "[REDACTED]"
84
- - (k)eep: Leave the value as-is
85
-
86
- This ensures sensitive information is handled securely in the generated prompt.
87
-
88
- ## Snippet Functionality
89
-
90
- For large files (>100 KB) and web content (>10,000 characters), kopipasta offers a snippet option:
91
-
92
- - For files: The first 50 lines or 4 KB (4,096 bytes), whichever comes first
93
- - For web content: The first 1,000 characters
94
-
95
- This helps manage the overall prompt size while still providing useful information about the content structure.
96
-
97
- ## Example output
98
-
99
- ```bash
100
- ❯ kopipasta . https://example.com/api-docs
101
-
102
- Directory: .
103
- Files:
104
- - __init__.py
105
- - main.py (120 KB, ~120000 chars, ~30000 tokens)
106
- - large_data.csv (5 MB, ~5000000 chars, ~1250000 tokens)
107
- - .env
108
-
109
- (y)es add all / (n)o ignore all / (s)elect individually / (q)uit? y
110
- main.py is large. Use (f)ull content or (s)nippet? s
111
- large_data.csv is large. Use (f)ull content or (s)nippet? s
112
- Added all files from .
113
- Added web content from: https://example.com/api-docs
114
-
115
- File and web content selection complete.
116
- Current prompt size: 10500 characters (~ 2625 tokens)
117
- Summary: Added 3 files from 1 directory and 1 web source.
118
-
119
- Detected environment variables:
120
- - API_KEY=12345abcde
121
-
122
- How would you like to handle API_KEY? (m)ask / (k)eep: m
123
-
124
- Enter the task instructions: Implement new API endpoint
125
-
126
- Generated prompt:
127
- # Project Overview
128
-
129
- ## Project Structure
130
-
131
- ```
132
- |-- ./
133
- |-- __init__.py
134
- |-- main.py
135
- |-- large_data.csv
136
- |-- .env
137
- ```
138
-
139
- ## File Contents
140
-
141
- ### __init__.py
142
-
143
- ```python
144
- # Initialize package
145
- ```
146
-
147
- ### main.py (snippet)
148
-
149
- ```python
150
- import os
151
- import pandas as pd
152
-
153
- API_KEY = os.getenv('API_KEY')
154
-
155
- def process_data(file_path):
156
- df = pd.read_csv(file_path)
157
- # Rest of the function...
158
-
159
- # More code...
160
- ```
161
-
162
- ### large_data.csv (snippet)
163
-
164
- ```
165
- id,name,value
166
- 1,John,100
167
- 2,Jane,200
168
- 3,Bob,150
169
- 4,Alice,300
170
- # ... (first 50 lines or 4 KB)
171
- ```
172
-
173
- ## Web Content
174
-
175
- ### https://example.com/api-docs (snippet)
176
-
177
- ```
178
- API Documentation
179
- Endpoint: /api/v1/data
180
- Method: GET
181
- Authorization: Bearer **********
182
- ...
183
- ```
184
-
185
- ## Task Instructions
186
-
187
- Implement new API endpoint
188
-
189
- ## Task Analysis and Planning
190
-
191
- Before starting, explain the task back to me in your own words. Ask for any clarifications if needed. Once you're clear, ask to proceed.
192
-
193
- Then, outline a plan for the task. Finally, use your plan to complete the task.
194
-
195
- Prompt has been copied to clipboard. Final size: 1500 characters (~ 375 tokens)
196
- ```
197
-
198
- ## License
199
-
200
- This project is licensed under the MIT License.
@@ -1,8 +0,0 @@
1
- kopipasta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- kopipasta/main.py,sha256=jDcsdCYE3u2EuMKZbcpkyayxgj5soLLm7XWbhG46Poo,34657
3
- kopipasta-0.17.0.dist-info/LICENSE,sha256=xw4C9TAU7LFu4r_MwSbky90uzkzNtRwAo3c51IWR8lk,1091
4
- kopipasta-0.17.0.dist-info/METADATA,sha256=4JjrjvjRucGOIlIEP3PvPDLefJ-Dq7JTDGd1HIbiraA,5646
5
- kopipasta-0.17.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
6
- kopipasta-0.17.0.dist-info/entry_points.txt,sha256=but54qDNz1-F8fVvGstq_QID5tHjczP7bO7rWLFkc6Y,50
7
- kopipasta-0.17.0.dist-info/top_level.txt,sha256=iXohixMuCdw8UjGDUp0ouICLYBDrx207sgZIJ9lxn0o,10
8
- kopipasta-0.17.0.dist-info/RECORD,,