Current area of focus so I don’t forget what I was doing.
2025/09/11 TODO: Could use org-agenda to collect the requisite headlines instead of enforcing a literal structure (by having them all under here). Yak shave that later.
TODO: Finish refreshing myself on what I need to catch up on here.
- Stub out 40s opcodes
- Add MSIZE with basic tests
- Refactor memory resizing to nextOp, adapt MSTORE tests, add KECCAK test for memory resizing
- KECCAK256 and surrounding utilities with many sanity checks along the way
- Add MSTORE8 with basic tests
- Add basic MLOAD with basic tests
- Part of MLOAD, need to get laundry right now though.
- Add GAS with tests, also correct argument ordering for recent JUMP, JUMPI, PC in expectEqual tests.
- Add annotations for recently implemented JUMP, JUMPI, and PC.
- JUMP/JUMPDEST implemented with basic tests. DynamicBitSetUnmanaged to pre-scan and construct bitset of valid JUMPDEST locations.
- More reading on JUMP and friends, yep we gotta do all the validation ourselves. Oh boy.
- Read associated YP information, need to implement JUMPDEST too and some more logic according to 9.4.3 so will do this later.
(9.4.3) Function D determines set of valid jump destinations. To be valid:
- Position must be occupied by a JUMPDEST instruction.
- JUMPDEST must not reside within data portion of any PUSH.
- Must appear within explicitly defined bytecode, and not the implicit infinite STOP padding.
Zig bit sets look good for this: https://ziglang.org/documentation/0.14.1/std/#std.bit_set
Not possible to know bytecode length at comptime, could set an upperbound but would require re-compiling if block gas limits change to allow more bytecode to be executed so DynamicBitSetUnmanaged from stdlib looks like a good pre-provided data structure for this.
Is it our job (as zevem) to assert 2 and 3? That would require ahead of time scanning the entire bytecode to execute or checking left-right of JUMPDEST to see if it resides within any PUSH (at every such call)
- State “TODO” from [2025-09-24 Wed 22:24]
If we need to do these checks it can get complicated
YES IT’S OUR JOB
Q: Do we have to analyse ahead of time or can we do it as we go and revert then and there? Potential issues perhaps? Do the ahead of time first since it’s simpler for now. I think we will have to since there’s no guarantee all of the bytecode will be explored so trying to determine during runtime (and not ahead of time) if a JUMPDEST is actually a JUMPDEST and not a byte in the data portion of a PUSH will be quite hard and cost more computationally than looking at all of the bytecode and creating a bitmask. Benchmark later, this seems like a hyper-optimisation.
What if it wants to set a program counter above u64?
Look at (160) 9.4.3 which defines how JUMP and JUMPDEST are required to interact. Continue from there.
- Add JUMPI with basic tests
- Add PC with basic tests
- State “TODO” from [2025-10-21 Tue 19:11]
Ref: YP Gas
TODO: Construct a list like this from the local subtree hierarchy here. That way I get both easy checkbox summary and state tracking via LOGBOOK which can only be done on headings.
- [ ] Intrinsic cost
- [ ] Subordinate message calls or contract creation
- [ ] CREATE
- [ ] CREATE2
- [ ] CALL
- [ ] CALLCODE
- [ ] Memory usage
C_mem(μ_i′) - C_mem(μ_i)
- Got actual dynamic gas (based on simpler memory size changes) actually working (correctness in terms of the price it reports to be tested still).
- Basic comptime function generation for memory size functions MVP.
Define memory size function for an opcode in the comptime MakeOpCodes tuple.
- Re-aqainting myself with gas charging again; implement hardcoded dynamic gas cost for MSTORE. This will need to be made generic essentially immediately.
- Migrate from BlockHeader struct with fields to methods on DummyEnv comptime interface
Good-enough disassembly-type logging until “real” and “better” (perhaps structured) logging implemented once zevem is 1.0. These are the functions traceOpNew and friends.
- Double-stroked N
- scalars are non-negative integers.
- Double-stroked B
- set of all byte sequences.
If N is subscripted (e.g. N_256) it is the set of all non-negative integers smaller than 2^256. If B is subscripted (e.g. B_32) it is the set of all byte sequences of length 32.
Square brackets index into, and/or reference individual components or subsequences.
Two adjacent dots (yellowpaper mistakenly calls ellipsis) denote inclusive range.
Modified and utilisable value of a thing is denoted prime ′ and intermediate values superscript one or two asterisks.
Empty sequence denoted () and empty set ∅ and these are not equal to each other.
Maps addresses (160-bit identifiers) and account states (RLP serialised data). Not stored on-chain, usually maintained in a modified Merkle Patricia tree (herein: trie) held by some database (“state database”).
Any of the formulas on page 4 which are relevant for just-the-EVM implementation.ENDAccounts have four fields. Accounts are empty if they have no code, zero nonce, and zero balance (f.14).
Scalar number of transactions sent from address. If account has associated code, number of contract-creations made by account.
Scalar amount of Wei owned by address.
256-bit hash for root node of trie that encodes the storage contents for account. Stylised: storageRoot.
More detailed storageRoot notes Yellowpaper pg 4 left-side.ENDHash of EVM code associated with account. Such code will be executed when a message call is received. Code is stored keyed by their Keccak-256 hash. Subscript c refers to the code-hash, stylised: codeHash.
Bold b refers to the concrete code. Thus KEC(b) = σ[a]_c.
If codeHash is hash of empty string (i.e. σ[a]_c = KEC(())) then the node is a simple account, aka “non-contract” account.
What is “node” here?? bottom of page 4 in ypEND Machine state notesENDμ_i: bottom of page 29 is the maximum number of words of active memory, and pg15 9.4.1 m: memory contents, a series of zeroes of size 2^256. i: active number of words in memory, counting continuously from zero.
Single cryptographically-signed instruction. Sender cannot be a contract. EIP-2718 introduces different transaction types (via a transaction envelope).
- 0
- legacy
- 1
- EIP-2930
- 2
- EIP-1559
Transactions can create new accounts with associated code (informally “contract creation”), or result in message calls.
All transactions have common fields:
EIP-2718 transaction type.
Scalar number of transactions sent by sender.
Scalar maximum amount of gas which could be used in executing this transaction. Paid up-front before any computation. Immutable during transaction.
160-bit address of the message call’s recipient. If contract creation then ∅ which here represents B_0 (set of all byte sequences of length zero).
Scalar amount of Wei to transfer to message call’s recipient. If contract creation then an endowment to newly created account.
Signature of transaction.
And for s, see Appendix F of yp for these definitions see also bottom left of page 5 of ypENDSender of transaction.
Scalar encoding of Y parity, and possibly chain ID. This is essentially the chainId and yParity fields but for legacy transactions. See EIP-155.
List of access entries to warm up.
What does that mean? Plus notes on the tuple information there.ENDChain ID, must be equal to network chain ID denoted β.
Signature Y parity.
What? yp pg5 left side.ENDType 2 transactions specify gas pricing differently to type 0 and type 1.
Single field.
gasPriceScalar maximum amount of Wei payable per unit of gas for all computation costs relating to execution of this transaction.
Two fields related to gas intended to explicitly limit priority fee magnitude.
maxFeePerGasScalar maximum amount of Wei payable per unit of gas for all computation costs relating to execution of this transaction.
maxPriorityFeePerGasScalar maximum amount of Wei payable to block’s fee recipient as an incentive to include the transaction.
Regardless of transaction type, a contract creation transaction has the field:
Unlimited size byte array of EVM bytecode for account initialisation procedure. Specifically, init is a code-fragment which returns a body (a second fragment of code); the body is executed each time the account receives a message call (whether from a transaction, or internal execution).
So, init is only executed once (at contract creation) and is discarded immediately thereafter.
For all transaction types which are message calls, there will be the field:
Unlimited size byte array specifying input data of the message call.
Fee schedule (Appendix G). The gasLimit T_g of a transaction is implicitly purchased from the sender’s account balance at the effective gas price before any computation is performed. At the end of the transaction any unused gas is refunded (at the same rate of purchase) to the sender’s account.
If this implicit purchase can not be made (not enough account balance) then the transaction is invalid.
effective gas price section 6ENDgas does not exist outside of the execution of a transaction i get that but what does the following (bottom-right pg8) then mean: Thus for accounts with trusted code associated, a relatively high gas limit may be set and left alone.ENDSince EIP-1559 every transaction must pay a base fee which is specified in Wei per unit of gas consumed and is immutable during each transaction in a given block. The Wei paid to meet the base fee is burned.
The base fee adjusts dynamically based on the previous block’s gas consumption relative to it’s gas target. The gas target is adjustable by validators.
If the previous block’s total gas consumption exceeds it’s gas target (i.e. high demand) the base fee is increased, and vice versa.
section 4.4 outlines how the base fee is set in detailENDTo incentivise validators to include transactions a priority fee, also specified in Wei per unit of gas consumed, is payable. The total fee for a transaction is the sum of the base fee and priority fee then multiplied by the total gas consumed. The priority fee is paid to a beneficiary address.
EIP-1559 transaction fields maxPriorityFeePerGas (maximum priority fee willing to pay), and maxFeePerGas (max total fee willing to pay, inclusive of priority and base fee). maxFeePerGas must be at least as high as the base fee to be included in a block. maxPriorityFeePerGas must not exceed maxFeePerGas.
Legacy, and EIP-2930 transaction field gasPrice (which also must be at least as high as the base fee for block inclusion) supplements base and priority fees (with less control). The extent to which gasPrice exceeds the base fee represents the implicit priority fee.
NotesENDTLOAD, TSTORE: https://eips.ethereum.org/EIPS/eip-1153 Same stack arguments as SLOAD and SSTORE.
MCOPY: https://eips.ethereum.org/EIPS/eip-5656
BLOBHASH: https://eips.ethereum.org/EIPS/eip-4844
BLOBBASEFEE: https://eips.ethereum.org/EIPS/eip-7516
Opcodes can have associated constant and/or dynamic gas prices and (with rare exceptions) are checked prior to opcode execution.
such exceptions are?ENDAppendix G defines tuples of constant gas fees and associated operations. Appendix H.1 concretely defines the gas cost function which covers all EVM instructions however further investigation per-opcode via Appendix H.2 (the EVM instruction set) is required to finally determine all associated gas fees for an opcode.
Section 9.2 outlines three circumstances where gas is payable:
- Intrinsic cost (usually constant, Appendices G, H.1).
- Subordinate message calls or contract creation (CREATE, CREATE2, CALL, CALLCODE).
- Increase in usage of memory.
(pg14 9.2) Opcodes which alter memory size pay gas according to the magnitude of memory modified in proportion to the smallest multiple of 32-bytes (i.e. WORD) required such that all indices (whether read or write) are included in said range. Essentially, any access to an area of memory 32-bytes greater than any previously indexed memory will incur a gas cost.
ROUGH: pg30 330: memory-expansion function M used to determine the new u_i size, some opcodes (e.g. MSTORE) have a specific function defined at their definition within H.2 for what u_i should be instead. Not all opcodes use M, or have their own inline u_i definition. pg29 328: memory-cost function C_mem simply computes the gas cost given memory size SOURCE?: Memory is byte-aligned (2^8) and not u256 aligned.
An enum of opcodes tagged with a u8 provides constant time lookup, but how to associate gas cost and stack deltas without going crazy on the size of the datastructure.
Is a multiarraylist but keyed by an enum an option?
A map keyed by an enum, backed by a bitfield and a dense array. If the enum is exhaustive but not dense, a mapping will be constructed from enum values to dense indices. This type does no dynamic allocation and can be copied by value.
An array keyed by an enum, backed by a dense array. If the enum is not dense, a mapping will be constructed from enum values to dense indices. This type does no dynamic allocation and can be copied by value.
A multiset of enum elements up to a count of usize. Backed by an EnumArray. This type does no dynamic allocation and can be copied by value.
A set of enum elements, backed by a bitfield. If the enum is exhaustive but not dense, a mapping will be constructed from enum values to dense indices. This type does no dynamic allocation and can be copied by value.
A multiset of enum elements up to CountSize. Backed by an EnumArray. This type does no dynamic allocation and can be copied by value.
Calling Tracy as follows:
fn someFunction() {
const zone = tracy.initZone(@src(), .{ .name = "foobar" });
}Will compute statistics for a zone named foobar as expected. If calling Tracy like this however:
fn someFunction() {
const zone = tracy.initZone(@src(), .{});
zone.name("foobar");
}Then the zone will be doubly-named as someFunction (from its enclosing scope) and foobar however statistics will only be computed under the someFunction name. This isn’t important in this simple example but imagine now a parameter is given to set the zone name:
fn someFunction(name: []const u8) {
const zone = tracy.initZone(@src(), .{});
zone.name(name);
}This will result in zones named as expected but no statistics will be computed for each name, they will all be under (statistically) the someFunction moniker. This can be beneficial in some scenarios, if statistics per name are desired Tracy must be called as:
fn someFunction(name: []const u8) {
const zone = tracy.initZone(@src(), .{ .name = name });
}Docs: https://ziglang.org/documentation/0.14.0/#toc-Build-Mode
| Mode | Optimise | Safety | Runtime Sp. | Repro. | Bin Size |
|---|---|---|---|---|---|
| Debug | Off | On | Slow | No | Large |
| ReleaseFast | On | Off | Fast | Yes | Large |
| ReleaseSafe | On | On | Medium | Yes | Large |
| ReleaseSmall | On (size) | Off | Medium | Yes | Small |
Docs: https://ziglang.org/documentation/0.14.0/#Zig-Build-System Docs: https://ziglang.org/learn/build-system/
It currently does run correctly, but things like GPA being renamed and ArrayLists being unmanaged by default now and the like need to be accounted for.
Release notes: https://ziglang.org/download/0.14.0/release-notes.html
- Non-aggregate types are those for which the
==is allowed. - Global variables can be initialised with the address of each other.
@src(std.builtin.SourceLocation) hasmodulefield now.std.cre-org: https://ziglang.org/download/0.14.0/release-notes.html#stdc-Reorganization
Deprecation list: https://ziglang.org/download/0.14.0/release-notes.html#List-of-Deprecations
https://ziglang.org/download/0.14.0/release-notes.html#Labeled-Switch
Already in-use, some central notes though:
switchstatement can be labeled,continuewithin such statements takes single operand which is treated as replacement for enclosing switch expressions operand thus explicitly stating the next prong to execute.- Can
breakfrom labeled switch which terminates its evaluation causing it to result in the given value tobreak. Thebreakmust be given the switch’s label to target it similarly to breaking out of blocks. - Labeled switches are not implicitly evaluated at comptime but such can be forced with the
comptimekeyword. - Semantically equivalent to switch inside a loop where a variable tracks switch operand and said variable is modified in each prong to control the subsequent prong to be executed.
Labeled switch designed to improve code-generation for hot loops such as those which dispatch instructions.
If operand to continue is comptime-known it is translated to an unconditional branch; this is a “perfectly predicted” branch and is very fast.
If operand to continue is runtime-known each continue can become a seperate conditional branch (ideally via shared jump table) back to the same set of conditional branch targets. This aids the CPU branch predictor by associating different branch instructions and their prediction data.
Zig’s tokeniser is 13% faster with labeled switches: ziglang/zig#21367
How to check and force that the jump table is shared for labeled switch runtime-known conditional branches?
Is the only implication of it NOT being shared that the binary size is larger due to duplicated jump tables? It should still be just as fast since it’s the same jump table data-wise no?
https://ziglang.org/download/0.14.0/release-notes.html#Decl-Literals
READ NEXT AFTER TODOs CREATED.
https://ziglang.org/download/0.14.0/release-notes.html#export-Operand-is-Now-a-Pointer
https://ziglang.org/download/0.14.0/release-notes.html#New-branchHint-Builtin-Replacing-setCold
https://ziglang.org/download/0.14.0/release-notes.html#Remove-Anonymous-Struct-Types-Unify-Tuples
https://ziglang.org/download/0.14.0/release-notes.html#FieldType-builtin
Similar to std.meta.FieldType, give a type and the name of one of it’s fields and get back the type of that field.
https://ziglang.org/download/0.14.0/release-notes.html#memcpy-Rules-Adjusted
https://ziglang.org/download/0.14.0/release-notes.html#DebugAllocator
GeneralPurposeAllocator used to rely on compile-time known page size (now removed as nonsensical). Now rewritten to make fewer active mappings and have better performance it is also renamed DebugAllocator.
Note: initialise with .init declaration literal and not .{} now.
https://ziglang.org/download/0.14.0/release-notes.html#SmpAllocator
https://ziglang.org/download/0.14.0/release-notes.html#Allocator-API-Changes-remap
https://ziglang.org/download/0.14.0/release-notes.html#ZON-Parsing-and-Serialization
https://ziglang.org/download/0.14.0/release-notes.html#Runtime-Page-Size
https://ziglang.org/download/0.14.0/release-notes.html#processChildcollectOutput-API-Changed
https://ziglang.org/download/0.14.0/release-notes.html#LLVM-Builder-API
Zig’s LLVM bitcode builder is now available at std.zig.llvm. Note that everything in the std.zig namespace is an implementation detail of the Zig compiler and isn’t subject to the same API stability and deprecation norms as the rest of std.
https://ziglang.org/download/0.14.0/release-notes.html#Embracing-Unmanaged-Style-Containers
- Managed container types (which internally associate an allocator for their lifetime) are deprecated and will be removed in the next Zig version (0.15.0).
- Unmanaged container types are now the norm and require passing (the same) allocator at every callsite where such a method requires it.
- Zig stdlib
ArrayHashMapWithAllocatorhappens to have an implementation of a “traditional” managed-style approach which (I think) is intended for the future. Unsure if that will also be discouraged / deprecated in 0.15.0 (as in, within stdlib itself). As users we’re free to create our own managed-style approaches.
For: std.sort.binarySort, std.sort.lowerBound, std.sort.upperBound, and std.sort.equalRange.
https://ziglang.org/download/0.14.0/release-notes.html#stdhash_map-gains-a-rehash-method
Currently unordered hash maps become slow when items are removed from them, in future Zig versions this will be fixed.
Array hash maps are free of this flaw.
https://ziglang.org/download/0.14.0/release-notes.html#Build-System https://ziglang.org/learn/build-system/
READ THIS ONE WHEN DONE MAKING TODOs:
- File System Watching
- New Package Hash Format
- WriteFile Step
- RemoveDir Step
- Fmt Step
https://ziglang.org/download/0.14.0/release-notes.html#Creating-Artifacts-from-Existing-Modules
Compile steps can be created from existing std.Build.Module objects. Easier to re-use now, e.g. a module which is a dependency of another can more easily have a test step created for it.
New APIs change usage of addExecutable, addTest etc. No longer pass root_source_file, target, optimize (etc) directly but a *std.Build.Module to the root_module field with said module taking aforementioned options instead.
https://ziglang.org/download/0.14.0/release-notes.html#addLibrary-Function
addLibrary replaces addSharedLibrary and addStaticLibrary.
https://ziglang.org/download/0.14.0/release-notes.html#Compiler
- Comptime import ZON.
- tokenizer: simplification and spec conformance
https://ziglang.org/download/0.14.0/release-notes.html#Linker
https://ziglang.org/download/0.14.0/release-notes.html#Fuzzer
https://ziglang.org/download/0.14.0/release-notes.html#UBSan-Runtime
Maybe (if things like tracy or valgrind for whatever reason aren’t good enough, which I doubt) how UBSan modifies things at compile time could be an approach for instrumentation etc etc. Again, doubt it since tracy/valgrind.
- State “TODO” from [2025-09-05 Fri 03:28]
Prior comment on EVM.mem
Zig 0.14.0 deprecates managed container types. Unmanaged container types must pass the same allocator at the callsite for methods which require it and do so every time. Perhaps create a wrapper (or appropriate custom type) later on to ease this (potential) burden. Zig std ArrayHashMapWithAllocator is an example of such.
- State “TODO” from [2025-08-12 Tue 19:11]
Can have a reader/writer and write into it (doesn’t have to be stdout) but any data structure I think. This could be a nice pattern to investigate using later.
- State “TODO” from [2025-08-12 Tue 19:42]
See test runners for an example API with the writing and in terms of logging scope the following resources:
- https://ziglang.org/documentation/0.14.1/#Standard-Library-Options
- https://ziglang.org/documentation/0.14.1/std/#std.log.scoped
- https://gist.github.com/kassane/a81d1ae2fa2e8c656b91afee8b949426
- State “DONE” from “TODO” [2025-08-12 Tue 19:12]
- State “DONE” from “TODO” [2025-08-24 Sun 18:17]
See: https://ziglang.org/documentation/master/std/#src/std/crypto/keccak_p.zig
The State function loops over some enums, that to function could use a labelled switch instead?
Any of that snapshot testing for everyone from tigerbeetle appropriate for our opcode unit tests later on?
See: https://tigerbeetle.com/blog/2024-05-14-snapshot-testing-for-the-masses/
Perhaps as a tagged enum? I forgot the proper term for this, have to double check notes. Either way want to replace the implicit error return of EVM.execute() from !void to somethin explicit.
It’s fine for now probably.
Yeah some overhead is added but how much idk, use poop or something to retroactively do this. Circa 2025-04-01 is when change to decodeOp occured (with tracy addition and so on).
It’s called poop or something, get a recipe for that and execute it to start basic benchmarking shit.
As part of adding tracy have a look at any non-trivial ways Zig’s own source is using labelled switches, mostly I’m curious about putting things like stack variable checks in what is currently decodeOp which is run as part of (almost) every continue statement. In that sense it functions similarly to the top of a while loop which is followed by a switch statement, except our usage of a labelled switch here keeps cpu branch predictability performance gains.
It’s fine for now, mostly a skeleton and should probably symlink to a central one for sharing and/or make it a little CLI tool for easier consumption. We’ll see.
Do we expect that any bytecode given to us is free from such errors and simply crash hard if encountered or do we surface those to the host? The compiled code is already going to check since Zig by default provides that orelse unreachable if we don’t specify anything. This could be a compile option (our custom errors) if there is in-fact any overhead and if in-fact we want to continue down that path.
Another thing to note is that.. what makes POP so special? What about DUP now.. what about every single other opcode? I think for now I may remove the POP custom error logic because it feels like the compiler that is feeding us bytecode, or the adept user who is handwriting such, should be responsible for that.
Things like trying to expand memory and that being an error we do surface (RETURN/REVERT) because that’s our job as the VM – thus, a difference in semantics I suppose.
E.g. generate tests for all of the N-style opcodes PUSH-N, DUP-N etc. Doesn’t really feel worth it versus literally writing them.
Maybe something like:
.{
// .bc for bytecode, .s for stack .s.l stack length, .s.i stack items from top etc.
.bc = "5f600a8100",
.s = .{
.l = 0,
.i = .{ 0, 0xa }
}
}All the uid mapping shit probably not required on Linux hosts since it’s not going macOS <==> Linux-VM <==> container with the macOS uid/gid being the ones we want to maintain.
Problem is when you want to do a lot of shell-stuff Just executes each line of the recipe in it’s own shell so if you have variables, or need the output of a prior command you need to have a recipe that is basically a heredoc shell script by adding #!/usr/bin/env bash to it.. at that point I’d rather just use a shell script directly.
Haven’t looked into fuzzing approaches yet; just found this while browsing other Zig things and it could be beneficial later: https://github.com/AFLplusplus/AFLplusplus and for Zig: https://github.com/kristoff-it/zig-afl-kit?tab=readme-ov-file
- State “TODO” from [2025-08-15 Fri 16:50]
Instead of evmBasicBytecode or most manual literal tests in source, perhaps replace them with test files on-disk which are read to execute EVM instructions and then the unit test in Zig code is about asserting expected values.
This feels like more of an experiment since the value in doing so is perhaps dubious versus in-source tests. Have to investigate. Not very important.
- State “TODO” from [2025-08-30 Sat 17:45]
Could do this to get nice auto-column aligned output wihtout having to write too much custom stuff.
0:0021(33) 60 PUSH1 gas=(3, 0, 78994)
0:0023(35) 7f PUSH32 gas=(3, 0, 78991)
printf '%s\n' $'0:0021(33)|60 PUSH1|gas=(3, 0, 78994)\n0:0023(35)|7f PUSH32|gas=(3, 0, 78991)\n0 -> left=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' | column -t -s '|'
0 -> left=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
printf '%s\n' $'0:0021(33)|60|PUSH1 gas=(3, 0, 78994)\n0:0023(35)|7faa|PUSH32 gas=(3, 0, 78991)\n| | |0 -> left=ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' | column -t -s '|'- Tramp using which instead of looping to find commands (as container now has it?)
- Tramp environment variables for container?
- Tramp use workdir argument for podmancp (make my own external method since a lot of customiation wanted here).
- Tramp gpg-agent
- Tramp git config
- Tramp magit signed commits and authenticated git remotes
- Tramp per container history file (i.e. don’t clobber general, global history file)
- Additionally, tramp history in its own history file to better distinguish user commands vs tramps?
- Tramp homedir for jam stuff, have it use a default username etc.
- What is this, looking for git repo? Stop it going up and up and up? seems to be when tramp runs `tramp_bundle_read_file_names` i.e. tramp-send-command (6) tramp_bundle_read_file_names
( (”home/jammy/project/build.zig” t t nil) (“/home/jammy/project.git” t t t) (”home/jammy” t t t) (“/home/jammy.git” nil nil nil) (“/.git” nil nil nil) )
echo “(” while read file; do quoted=`echo “$file” | sed -e “s/"\\\\"”` printf “(%b” “"$quoted"” if test -e “$file”; then printf ” %b” t; else printf ” %b” nil; fi if test -r “$file”; then printf ” %b” t; else printf ” %b” nil; fi if test -d “$file”; then printf ” %b) ” t; else printf ” %b) ” nil; fi done echo “)” } 2>/dev/null; echo tramp_exit_status $?
so with tramp_bundle_read_file_names is vc.el asking it to check those paths? Cos it looks like the tramp command is GIVEN the paths home/jammy/project/build.zig and /home/jammy/project.git and home/jammy and /home/jammy.git and /.git but what is giving it those paths in the first place?
purpose of LOGNAME env var?
git –no-pager ls-files -c -z – build.zig
Emacs environment replacement, what is $d used for after a remote connection has been established?
Better function for tramp_bundle_read_file_names called by tramp-maybe-send-script
tramp-maybe-open-connection # Setup connection for tramp-open-shell # Opening remote shell tramp-open-connection-setup-interactive-shell # Setting up remote shell environment and # Setting default environment
Stretch goal:
- Email tramp-devel and suggest using printf instead of echo, and suggest using $() instead of “ syntax.
perl script completions, find out what these tuples are. The script it sends for tramp-send-command #tramp_perl_file_name_all_completions /home/jammy example output is: ( (“./” ”home/jammy.” t t t) (“../” ”home/jammy..” t t t) (“.bash_history” ”home/jammy.bash_history” nil t t) (“.bashrc” ”home/jammy.bashrc” nil t t) (“.bash_profile” ”home/jammy.bash_profile” nil t t) (“project/” ”home/jammy/project” t t t) (“.bash_logout” “/home/jammy.bash_logout” nil t t) )
and the script is:
\perl -e ’
$dir = $ARGV[0];
if ($dir ne “/”) {
18:52:25.142228 tramp-send-command (6) # ( cd home/jammy/project && unset GIT_DIR && env INSIDE_EMACS\=31.0.50\,tramp\:2.8.0-pre GIT_LITERAL_PATHSPECS\=1 GIT_OPTIONAL_LOCKS\=0 git –no-pager ls-tree –name-only -z HEAD – project-todo.org </dev/null 2>/dev/null; echo tramp_exit_status $? )
What is `uncompface` that it tries to execute? lone `nil` text in Messages and vc refresh error, the tramp logs for these lines in Messages: File is missing: podmancp:jammy@jam-zevem:/home/jammy/project.gitmodules nil
Tramp: Inserting ‘/podmancp:jammy@jam-zevem:/home/jammy/project/project-todo.org’…done End of file during parsing: End of file during parsing,
VC refresh error: (end-of-file “”)
Tramp: Checking ‘vc-registered’ for /podmancp:jammy@jam-zevem:/home/jammy/project/project-todo.org…done
Appear to be:
18:07:54.913758 tramp-send-command (6) # tramp_bundle_read_file_names <<’e7381d37826e413f7338377bdf35cb06’ 2>/dev/null; echo tramp_exit_status $?
home/jammy/project/build.zig
/home/jammy/project.git
home/jammy
/home/jammy.git
/.git
e7381d37826e413f7338377bdf35cb06
18:07:54.974272 tramp-wait-for-regexp (6) #
(
(”home/jammy/project/build.zig” t t nil)
(“/home/jammy/project.git” t t t)
(”home/jammy” t t t)
(“/home/jammy.git” nil nil nil)
(“/.git” nil nil nil)
)
tramp_exit_status 0
///94b4655c39f14eb594acd8c8e974e8cd#$
18:07:54.976193 tramp-send-command (6) # test -d /home/jammy/project 2>/dev/null; echo tramp_exit_status
------ONE 2% - vc-working-revision 56 2% - vc-call-backend 56 2% - vc-git-working-revision 56 2% - vc-git–rev-parse 56 2% - vc-git–out-ok 56 2% - vc-git–call 56 2% - process-file 56 2% - tramp-file-name-handler 56 2% - apply 56 2% - tramp-sh-file-name-handler 56 2% - tramp-sh-handle-process-file 55 2% - tramp-send-command-and-check 55 2% - tramp-send-command 51 2% - tramp-wait-for-output 51 2% - tramp-wait-for-regexp 31 1% - tramp-accept-process-output 31 1% accept-process-output 20 0% sit-for 4 0% - tramp-message 4 0% - apply 4 0% - tramp-debug-message 4 0% write-region 1 0% - expand-file-name 1 0% - tramp-file-name-handler 1 0% - apply 1 0% - tramp-sh-file-name-handler 1 0% - tramp-sh-handle-expand-file-name 1 0% - tramp-drop-volume-letter 1 0% - replace-regexp-in-string 1 0% concat 1 ------/
-----TWO
- vc-mode-line 52 2% - vc-call-backend 52 2% - vc-git-mode-line-string 52 2% - vc-git–symbolic-ref 52 2% - vc-git–run-command-string 51 2% - vc-git–out-ok 51 2% - vc-git–call 51 2% - process-file 51 2% - tramp-file-name-handler 51 2% - apply 51 2% - tramp-sh-file-name-handler 51 2% - tramp-sh-handle-process-file 51 2% - tramp-send-command-and-check 49 2% - tramp-send-command 45 2% - tramp-wait-for-output 45 2% - tramp-wait-for-regexp 28 1% - tramp-accept-process-output 28 1% accept-process-output 14 0% sit-for 3 0% - tramp-message 3 0% - apply 3 0% - tramp-debug-message 3 0% write-region 4 0% - tramp-message 4 0% - apply 4 0% - tramp-debug-message 4 0% write-region 1 0%
------/
------THREE
- vc-call-backend 85 4% - vc-git-find-file-hook 85 4% - vc-state 85 4% - vc-state-refresh 85 4% - vc-call-backend 85 4% - vc-git-state 85 4% - vc-git–run-command-string 81 3% - vc-git–out-ok 81 3% - vc-git–call 81 3% - process-file 81 3% - tramp-file-name-handler 81 3% - apply 81 3% - tramp-sh-file-name-handler 81 3% - tramp-sh-handle-process-file 81 3% - tramp-send-command-and-check 81 3% - tramp-send-command 79 3% - tramp-wait-for-output 79 3% - tramp-wait-for-regexp 54 2% - tramp-accept-process-output 54 2% - accept-process-output 1 0% syntax-ppss-flush-cache 25 1% sit-for 2 0% - tramp-message 2 0% - apply 2 0% - tramp-debug-message 2 0%
-----/
-----FOUR
- tramp-run-real-handler
179 8% - vc-registered 177 8% - mapc 177 8% - #<byte-code-function 6D0> 177 8% - vc-call-backend 177 8% - vc-git-registered 144 7% - vc-git–out-ok 144 7% - vc-git–call 144 7% - process-file 144 7% - tramp-file-name-handler 144 7% - apply 144 7% - tramp-sh-file-name-handler 144 7% - tramp-sh-handle-process-file 143 6% - tramp-send-command-and-check 143 6% - tramp-send-command 134 6% - tramp-wait-for-output 134 6% - tramp-wait-for-regexp 71 3% - tramp-accept-process-output 71 3% accept-process-output 60 2% sit-for 2 0% - tramp-message 2 0% - apply 2 0% - tramp-debug-message 2 0% write-region 1 0% - tramp-check-for-regexp 1 0% tramp-search-regexp 9 0% - tramp-message 9 0% - apply 9 0% - tramp-debug-message 6 0% write-region 2 0% whitespace–update-bob-eob 1 0% - tramp-get-debug-buffer 1 0% - tramp-debug-buffer-name 1 0% --------/
------FIVE
- timer-event-handler 793 38% - apply 791 38% - auto-revert-buffers 791 38% - apply 791 38% - auto-revert-buffers@buffer-list-filter 791 38% - if 791 38% - funcall 791 38% - #<native-comp-function auto-revert-buffers> 784 38% - auto-revert-buffer 784 38% - auto-revert-handler 784 38% - vc-refresh-state 647 31% - vc-backend 646 31% - vc-registered 642 31% - tramp-file-name-handler 642 31% - apply 642 31% - tramp-sh-file-name-handler 642 31% - tramp-sh-handle-vc-registered 463 22% - tramp-bundle-read-file-names 463 22% - tramp-send-command-and-check 463 22% - tramp-send-command 454 22% - tramp-wait-for-output 454 22% - tramp-wait-for-regexp 266 12% - tramp-accept-process-output 261 12% accept-process-output 2 0% - tramp-get-connection-property 1 0% tramp-file-name-unify 1 0% - #<byte-code-function EF0> 1 0% - tramp-flush-connection-property 1 0% tramp-get-hash-table 182 8% sit-for 5 0% - tramp-check-for-regexp 5 0% tramp-search-regexp 1 0% - tramp-message 1 0% - apply 1 0% - tramp-debug-message 1 0% write-region 8 0% - tramp-message 8 0% - apply 8 0% - tramp-debug-message 7 0% - write-region 5 0% - select-safe-coding-system 5 0% - find-auto-coding 5 0% auto-coding-alist-lookup 1 0% - tramp-maybe-open-connection 1 0% - tramp-get-connection-process 1 0% - tramp-get-connection-name 1 0% - tramp-buffer-name 1 0% tramp-file-name-host-port 179 8%
---------/
tramp-list-connections tramp-compat-seq-keep apply fun to seq and return non-nil results fun: the lambda defined there seq: (hash-table-keys tramp-cache-data)
tramp-vc-registered-file-names