Skip to content

Instantly share code, notes, and snippets.

@ryuukk
Created March 25, 2025 15:31
Show Gist options
  • Save ryuukk/df54a08be96cd3c080cf664ada0d099b to your computer and use it in GitHub Desktop.
Save ryuukk/df54a08be96cd3c080cf664ada0d099b to your computer and use it in GitHub Desktop.
import sublime
import sublime_plugin
import re
class GetFunctionScopeCommand(sublime_plugin.TextCommand):
def run(self, edit):
view = self.view
cursor_pos = view.sel()[0].begin()
current_line_region = view.line(cursor_pos)
current_line = view.substr(current_line_region)
# Determine syntax (language)
syntax = view.syntax().scope.split('.')[-1] if view.syntax() else "unknown"
# Find the function name and scope range
func_name, scope_start, scope_end = self.deduce_function_scope(view, cursor_pos, syntax)
if func_name and scope_start and scope_end:
sublime.message_dialog(
f"Function: {func_name}\n"
f"Scope: Lines {scope_start+1}-{scope_end+1}"
)
# Highlight the scope (optional)
view.add_regions("func_scope", [sublime.Region(scope_start, scope_end)], "comment", "", sublime.DRAW_NO_OUTLINE)
else:
sublime.message_dialog("Not inside a function.")
def deduce_function_scope(self, view, cursor_pos, syntax):
# Search backward for function declaration
func_decl_pattern = self.get_function_pattern(syntax)
if not func_decl_pattern:
return None, None, None
# Iterate backward to find the nearest function declaration
line_regions = reversed(view.lines(sublime.Region(0, cursor_pos)))
for line_region in line_regions:
line_text = view.substr(line_region).strip()
match = re.match(func_decl_pattern, line_text)
if match:
func_name = match.group(1)
scope_start = line_region.begin()
# Find scope end based on syntax
scope_end = self.find_scope_end(view, line_region, syntax)
return func_name, scope_start, scope_end
return None, None, None
def get_function_pattern(self, syntax):
# Regex patterns for function declarations (customize as needed)
patterns = {
"python": r'^\s*def\s+(\w+)\s*\(',
"javascript": r'function\s+(\w+)\s*\(.*\)\s*\{?',
"php": r'function\s+(\w+)\s*\(.*\)\s*\{?',
"ruby": r'def\s+(\w+)\s*',
}
return patterns.get(syntax.lower())
def find_scope_end(self, view, decl_region, syntax):
# Find end of function scope (braces or indentation)
if syntax == "python":
return self.find_python_scope_end(view, decl_region)
else:
return self.find_brace_scope_end(view, decl_region)
def find_brace_scope_end(self, view, decl_region):
# Match curly braces for languages like JS/PHP/C++
start_pos = decl_region.end()
brace_count = 0
for pos in range(start_pos, view.size()):
char = view.substr(pos)
if char == '{':
brace_count += 1
elif char == '}':
brace_count -= 1
if brace_count == 0:
return pos + 1 # Include closing brace
return decl_region.end() # Fallback
def find_python_scope_end(self, view, decl_region):
# Match indentation level for Python
decl_line = view.line(decl_region)
base_indent = len(view.substr(decl_line).expandtabs(4)) - len(view.substr(decl_line).lstrip().expandtabs(4))
next_line = decl_line.end() + 1
while next_line < view.size():
line_region = view.line(next_line)
line_text = view.substr(line_region)
if not line_text.strip():
next_line = line_region.end() + 1
continue
current_indent = len(line_text.expandtabs(4)) - len(line_text.lstrip().expandtabs(4))
if current_indent <= base_indent:
return line_region.begin() - 1
next_line = line_region.end() + 1
return view.size()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment