|
diff --git a/editor.go b/editor.go
|
| ... |
| 1625 |
return string(line[start:end]) |
1625 |
return string(line[start:end]) |
| 1626 |
} |
1626 |
} |
| 1627 |
|
1627 |
|
|
|
1628 |
func (e *Editor) ModifyNumberUnderCursor(delta int) { |
|
|
1629 |
b := e.activeBuffer() |
|
|
1630 |
if b == nil || b.readOnly { |
|
|
1631 |
return |
|
|
1632 |
} |
|
|
1633 |
|
|
|
1634 |
e.saveState() |
|
|
1635 |
cursors := e.getSortedCursorsDesc() |
|
|
1636 |
modified := false |
|
|
1637 |
|
|
|
1638 |
for _, c := range cursors { |
|
|
1639 |
if c.Y >= len(b.buffer) { |
|
|
1640 |
continue |
|
|
1641 |
} |
|
|
1642 |
line := b.buffer[c.Y] |
|
|
1643 |
if len(line) == 0 { |
|
|
1644 |
continue |
|
|
1645 |
} |
|
|
1646 |
|
|
|
1647 |
x := c.X |
|
|
1648 |
if x >= len(line) { |
|
|
1649 |
x = len(line) - 1 |
|
|
1650 |
} |
|
|
1651 |
|
|
|
1652 |
isDigit := func(r rune) bool { return r >= '0' && r <= '9' } |
|
|
1653 |
|
|
|
1654 |
// Helper to check if there is a valid number at or around a given position |
|
|
1655 |
checkAt := func(pos int) (int, int) { |
|
|
1656 |
if pos < 0 || pos >= len(line) { |
|
|
1657 |
return -1, -1 |
|
|
1658 |
} |
|
|
1659 |
// Case 1: Position is on a word character. |
|
|
1660 |
if e.isWordChar(line[pos]) { |
|
|
1661 |
wStart := pos |
|
|
1662 |
for wStart > 0 && e.isWordChar(line[wStart-1]) { |
|
|
1663 |
wStart-- |
|
|
1664 |
} |
|
|
1665 |
wEnd := pos |
|
|
1666 |
for wEnd < len(line) && e.isWordChar(line[wEnd]) { |
|
|
1667 |
wEnd++ |
|
|
1668 |
} |
|
|
1669 |
|
|
|
1670 |
// Check if the entire word is digits. |
|
|
1671 |
allDigits := true |
|
|
1672 |
for i := wStart; i < wEnd; i++ { |
|
|
1673 |
if !isDigit(line[i]) { |
|
|
1674 |
allDigits = false |
|
|
1675 |
break |
|
|
1676 |
} |
|
|
1677 |
} |
|
|
1678 |
|
|
|
1679 |
if allDigits { |
|
|
1680 |
s := wStart |
|
|
1681 |
en := wEnd |
|
|
1682 |
// Check for leading minus sign. |
|
|
1683 |
if s > 0 && line[s-1] == '-' { |
|
|
1684 |
// Ensure the minus isn't preceded by another word character. |
|
|
1685 |
if s == 1 || !e.isWordChar(line[s-2]) { |
|
|
1686 |
s-- |
|
|
1687 |
} |
|
|
1688 |
} |
|
|
1689 |
return s, en |
|
|
1690 |
} |
|
|
1691 |
} else if line[pos] == '-' && pos+1 < len(line) && isDigit(line[pos+1]) { |
|
|
1692 |
// Case 2: Position is on a minus sign followed by a digit. |
|
|
1693 |
wStart := pos + 1 |
|
|
1694 |
wEnd := pos + 1 |
|
|
1695 |
for wEnd < len(line) && e.isWordChar(line[wEnd]) { |
|
|
1696 |
wEnd++ |
|
|
1697 |
} |
|
|
1698 |
|
|
|
1699 |
// Check if the word following the minus sign is all digits. |
|
|
1700 |
allDigits := true |
|
|
1701 |
for i := wStart; i < wEnd; i++ { |
|
|
1702 |
if !isDigit(line[i]) { |
|
|
1703 |
allDigits = false |
|
|
1704 |
break |
|
|
1705 |
} |
|
|
1706 |
} |
|
|
1707 |
|
|
|
1708 |
if allDigits { |
|
|
1709 |
return pos, wEnd |
|
|
1710 |
} |
|
|
1711 |
} |
|
|
1712 |
return -1, -1 |
|
|
1713 |
} |
|
|
1714 |
|
|
|
1715 |
start := -1 |
|
|
1716 |
end := -1 |
|
|
1717 |
|
|
|
1718 |
// 1. Check if there's a number at the current cursor position. |
|
|
1719 |
start, end = checkAt(x) |
|
|
1720 |
|
|
|
1721 |
// 2. If not, search forward on the current line. |
|
|
1722 |
if start == -1 { |
|
|
1723 |
for i := x + 1; i < len(line); i++ { |
|
|
1724 |
// Optimization: only check if it looks like a number start. |
|
|
1725 |
if isDigit(line[i]) || (line[i] == '-' && i+1 < len(line) && isDigit(line[i+1])) { |
|
|
1726 |
start, end = checkAt(i) |
|
|
1727 |
if start != -1 { |
|
|
1728 |
break |
|
|
1729 |
} |
|
|
1730 |
} |
|
|
1731 |
} |
|
|
1732 |
} |
|
|
1733 |
|
|
|
1734 |
if start == -1 { |
|
|
1735 |
continue |
|
|
1736 |
} |
|
|
1737 |
|
|
|
1738 |
numStr := string(line[start:end]) |
|
|
1739 |
val, err := strconv.Atoi(numStr) |
|
|
1740 |
if err != nil { |
|
|
1741 |
continue |
|
|
1742 |
} |
|
|
1743 |
|
|
|
1744 |
newVal := val + delta |
|
|
1745 |
newStr := strconv.Itoa(newVal) |
|
|
1746 |
newRunes := []rune(newStr) |
|
|
1747 |
|
|
|
1748 |
// Replace the number in the buffer. |
|
|
1749 |
newLine := append(line[:start], append(newRunes, line[end:]...)...) |
|
|
1750 |
b.buffer[c.Y] = newLine |
|
|
1751 |
|
|
|
1752 |
// Handle syntax update. |
|
|
1753 |
if b.syntax != nil { |
|
|
1754 |
deletedBytes := uint32(len(string(line[start:end]))) |
|
|
1755 |
addedBytes := uint32(len(string(newRunes))) |
|
|
1756 |
oldColBytes := b.getLineByteOffset(line, start) |
|
|
1757 |
newColBytes := b.getLineByteOffset(newLine, start) |
|
|
1758 |
b.handleEdit(c.Y, start, deletedBytes, addedBytes, c.Y, oldColBytes+deletedBytes, c.Y, newColBytes+addedBytes) |
|
|
1759 |
} |
|
|
1760 |
|
|
|
1761 |
// Keep cursor on the number (at its start). |
|
|
1762 |
c.X = start |
|
|
1763 |
modified = true |
|
|
1764 |
} |
|
|
1765 |
|
|
|
1766 |
if modified { |
|
|
1767 |
if b.syntax != nil { |
|
|
1768 |
b.syntax.Reparse([]byte(b.toString())) |
|
|
1769 |
} |
|
|
1770 |
e.markModified() |
|
|
1771 |
} |
|
|
1772 |
} |
|
|
1773 |
|
| 1628 |
func (e *Editor) isPathChar(r rune) bool { |
1774 |
func (e *Editor) isPathChar(r rune) bool { |
| 1629 |
return e.isWordChar(r) || r == '/' || r == '.' || r == '-' || r == '_' || r == '~' || r == '\\' || r == ':' |
1775 |
return e.isWordChar(r) || r == '/' || r == '.' || r == '-' || r == '_' || r == '~' || r == '\\' || r == ':' |
| 1630 |
} |
1776 |
} |
| ... |