Searching recursively all files with the given extension:
find . -name "*.orig"
Searching all files containing the given text (source):
grep -Rn . -e "palavra"
Huge life saver.
Searching recursively all files with the given extension:
find . -name "*.orig"
Searching all files containing the given text (source):
grep -Rn . -e "palavra"
Huge life saver.
On further researching of my previous idea of creating a Zustand + Immer wrapper, I found a very interesting technique straight from Zustand docs, where all the methods are simply free functions declared outside the store, called no store actions. I was already using this to declare private store methods, but it never occurred me to use it for all methods.
Since it officially has no downsides, I applied this idea to append the actions directly to the hook itself, so we don’t need to import each free function. The problem is that the hook has a couple methods itself, plus the inherent ones to any function object. So the result is very polluted. So I decided to adopt a convention of prefixing every action with $
.
But conventions are easy to break. So I implemented a reduce
to prefix each method name with #
. But then TypeScript could not infer the type anymore, so I had to dig and type it manually with key remapping, and finally I got this implementation:
import {create, StateCreator} from 'zustand'; import {devtools} from 'zustand/middleware'; import {immer} from 'zustand/middleware/immer'; export function createStore<T extends object, U extends object>( initialState: T, actions: StateCreator< T, [['zustand/devtools', never], ['zustand/immer', never]], [['zustand/immer', never], ['zustand/devtools', never]], U >, ) { const store = create( devtools( immer(() => initialState), {name: Math.random().toString(36).slice(2), serialize: true}, ), ); type WithPrefix<T> = { [K in keyof T as K extends string ? `$${K}` : never]: T[K]; }; const actionsOrig = actions(store.setState, store.getState, store); const actionsPrefixed = Object.entries(actionsOrig).reduce( (accum, [k, v]) => ({...accum, ['$' + k]: v}), {} as WithPrefix<typeof actionsOrig>, ); return Object.assign(store, actionsPrefixed); }
This creator allows us to call actions directly, without the hook. They’ll be automatically prefixed with $
:
const useFoo = createStore('Foo', { name: '', }, (set, get) => ({ setName(name: string): void { set(state => { state.name = name; }); }, })); function App() { const name = useFoo(s => s.name); return <div> <span>{name}</span> <button onClick={() => useFoo.$setName('Joe')}</button> Change </button> </div>; }
That $
prefix gives me bad Vue vibes. Let’s see if I can get along with it, because I was able to develop a DX which is exactly what I was looking for.
For my working VM, after ditching the sluggish Ubuntu 22 for the crazy good Mint Cinnamon 21, one of the customizations I wanted to make was the maximum width of the taskbar buttons. They seemed to narrow, while a lot of room was available.
After a couple minutes of searching, I found a direction in the Mint forums. The proposed solution is for Mint 20 – for Mint 21, it has a minor difference.
Edit, as root, the following file:
/usr/share/cinnamon/applets/grouped-window-list@cinnamon.org/constants.js
The value we’re after is MAX_BUTTON_WIDTH
, which I increased from 150
to 210
.
What caught my attention, though, is how all the layout building stuff is JavaScript.
A deb package can be installed on Linux by running:
sudo dpkg -i Package.deb
However, the installation may fail because dependencies are missing. In such cases, I found a tip which appears to work very well. After the failed dpkg
command, run:
sudo apt-get -f install
This a shorthand for --fix-broken
, and installs the dependencies and completes the aborted dpkg
installation. Like magic.
Vue 3 has many idiosyncrasies, among them the overlapping ref
and reactive
constructs. One of the main differences is that reactive
content cannot be replaced. One StackOverflow answer proposes using Object.assign
, but it will replace all nested references, losing them all.
I ended up writing my own version of a recursive function to replace each value inside an object, so I won’t need to deal with the muddy details ever again:
/** * Recursively copies each field from src to dest, avoiding the loss of * reactivity. Used to copy values from an ordinary object to a reactive object. */ export function deepAssign<T extends object>(destObj: T, srcObj: T): void { const dest = destObj; const src = toRaw(srcObj); if (src instanceof Date) { throw new Error('[deepAssign] Dates must be copied manually.'); } else if (Array.isArray(src)) { for (let i = 0; i < src.length; ++i) { if (src[i] === null) { (dest as any)[i] = null; } else if (src[i] instanceof Date) { (dest as any)[i] = new Date(src[i].getTime()); } else if (Array.isArray(src[i]) || typeof src[i] === 'object') { deepAssign((dest as any)[i], src[i]); } else { (dest as any)[i] = toRaw(src[i]); } } } else if (typeof src === 'object') { for (const k in src) { if (src[k] === null) { (dest as any)[k] = null; } else if (src[k] instanceof Date) { (dest[k] as any) = new Date((src[k] as any).getTime()); } else if (Array.isArray(src[k]) || typeof src[k] === 'object') { deepAssign(dest[k] as any, src[k] as any); } else { (dest[k] as any) = toRaw(src[k]); } } } else { throw new Error('[deepAssign] Unknown type: ' + (typeof src)); } }
Another problem with reactive
is that, to avoid two variables pointing to the same point, we must deep clone an object when creating the object. I also wrote a function to deal with that:
/** * Deeply clones an object, eliminating common references. Used to create a * reactive object by copying from an ordinary object. */ export function deepClone<T>(origObj: T): T { const obj = toRaw(origObj); if (obj === undefined || obj === null || typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') { return obj; } else if (Array.isArray(obj)) { return obj.reduce((acum, item) => [...acum, deepClone(item)], []); } else if (obj instanceof Date) { return new Date(obj.getTime()) as unknown as T; } else if (typeof obj === 'object') { return Object.entries(obj).reduce( (acum, [key, val]) => ({...acum, [key]: deepClone(val)}), {}) as T; } else { throw new Error('[deepClone] Tipo desconhecido: ' + (typeof obj)); } }
I remember from my MobX days some people saying that working with reactive variables can be tricky. Now I can clearly see why.
While researching React stores automation, I wondered whether it would be possible to have a TypeScript function to set the value of an object by the name of its property, with correctly typed parameters, of course.
Turns out, it is
export function setField< T extends object, K extends keyof T, >(o: T, k: K, v: T[K]): void { o[k] = v; }
The function above works perfectly with interfaces:
interface Person { name: string; age: number; } const p: Person = { name: 'Joe', age: 42 }; setField(p, 'name', 'foo');
Three months ago I wrote an utility function to deal with write-only atoms in Jotai. To go with it, today I wrote a function to deal with read-only atoms, so now I have:
import {Atom, useAtom, WritableAtom} from 'jotai'; /** * Syntactic sugar to useAtom() for read-only atoms. */ export function useReadAtom<V>(a: Atom<V>) { const [val] = useAtom(a); return val; } /** * Syntactic sugar to useAtom() for write-only atoms. */ export function useWriteAtom<V, A extends unknown[], R>(a: WritableAtom<V, A, R>) { const [_, setFunc] = useAtom(a); return setFunc; }
It’s worth mentioning that useReadAtom
also works for derived atoms, used for computed values.
I’ve been trying to find a way for computed values in Zustand for a while. The general recommended way is using a custom hook, according to Daishi Kato himself. The issue with this approach, however, is that your computed logic will be completely alienated from the store itself.
I just found a neat approach which seems to work: using a nested object inside the store itself, as pointed in this highly cheered comment. Below is a fully typed example:
import {create} from 'zustand'; import {combine} from 'zustand/middleware'; import {immer} from 'zustand/middleware/immer'; export interface Person { name: string; age: number; } const usePeople = create(immer( combine({ people: [] as Person[], }, (set, get) => ({ $computed: { get count(): number { return get().people.length; }, }, addNew(name: string, age: number): void { set(state => { state.people.push({name, age}); }); }, })), )); export default usePeople;
The tradeoff, as benchmarked by myself, is that this $computed
getters are not cached and will run every time the state changes, in addition to every time they are requested – which happens when the component re-renders. The ordinary custom hook approach runs only when they are requested. So, there is a performance penalty, which can be huge if the logic is too demanding.
While analyzing a bug in WinSafe, I had to test its compilation on the i686 platform. Without knowing, I already had it installed together with my MSVC toolchain, and I just needed a few commands in order to pull it out:
List all available toolchains:
rustup toolchain list
Which gave me:
stable-i686-pc-windows-msvc stable-x86_64-pc-windows-msvc (default) nightly-x86_64-pc-windows-msvc
Then choose other than the default toolchain:
cargo +stable-i686-pc-windows-msvc c
After performing all the tests, it’s a good idea to clean all the build artifacts:
cargo clean
Note that, if the toolchain is not present, it may have to be installed.
Every atom in Jotai, when called through its useAtom
primitive, returns a tuple of value + setter, just like React’s own useState
. In a Jotai write-only atom, however, there is no value, so the canonical call is:
const [_, setVal] = useAtom(myValAtom);
In order to get rid of the verbose underscore, and thus the whole useless tuple, I wrote the following function:
import {WritableAtom} from 'jotai'; /** * Syntactic sugar to useAtom() for write-only atoms. */ export function useWriteAtom<V, A extends unknown[], R>(a: WritableAtom<V, A, R>) { const [_, setFunc] = useAtom(a); return setFunc; }
The atom type was copied straight from Jotai’s TypeScript definitions, so the type inference works seamlessly. The example now can be written as:
const setVal = useWriteAtom(myValAtom);
Suppose you want implement Display
and Debug
traits for your struct, but the output is the same. Instead of copy & paste the implementation, you can delegate the implementation by casting the Self
type to the trait type:
impl std::fmt::Debug for MyStruct { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "MyStruct"); } } impl std::fmt::Display for HRESULT { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { <Self as std::fmt::Debug>::fmt(self, f) // delegate } }
As a reminder, the Self
casting can be useful in other situations.
While prospecting the use of useState
with the great Immer, I ended up finding the small use-immer package, which unifies both things. However, it doesn’t have proper TypeScript typings.
So I wrote my own hook to perform this task: just like useState
, it returns a value and a setter, but the setter’s argument is a mutable state, automatically wired to produce
, and all that using a generic argument for proper typing:
import {useCallback, useState} from 'react'; import {Draft, produce} from 'immer'; export function useStateImmer<T>(initialState: T | (() => T)): [ T, (updater: (draft: Draft<T>) => void) => void, ] { const [obj, setObj] = useState(initialState); const setObjProduce = useCallback((updater: (draft: Draft<T>) => void): void => { setObj(curState => { return produce(curState, draft => { updater(draft); }); }); }, [setObj]); return [obj, setObjProduce]; }
Note that the returned setter function is identity, since it’s guarded by an useCallback
call.