1 पॉइंट द्वारा GN⁺ 1 시간 전 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • zig fmt को फ़ाइल में पहले से मौजूद syntax shape को देखकर उसी कोड को कई layouts में व्यवस्थित करने वाले एक steerable formatter की तरह इस्तेमाल किया जा सकता है
  • function calls में trailing comma की मौजूदगी या अनुपस्थिति नतीजा बदल देती है; comma न हो तो यह एक ही लाइन में समेट देता है, और comma हो तो arguments को हर लाइन में रखता है
  • वास्तविक workflow यह है कि पहले मनचाहा code layout तय किया जाए, फिर कुछ commas जोड़े जाएँ, और उसके बाद format shortcut दबाया जाए ताकि zig fmt बाकी काम कर दे
  • arrays में trailing comma के साथ-साथ पहले line break की स्थिति भी प्रतिबिंबित होती है; अगर पहला line break तीसरे item के बाद है, तो items 3-3 के समूह में align होते हैं
  • ++ array concatenation का सावधानी से उपयोग करने पर हर लाइन में items की संख्या अलग रखी जा सकती है, और subprocess को --key और value pairs भेजते समय fixed argument array और option-pair array को जोड़कर उन्हें align किया जा सकता है

zig fmt को steer करने का तरीका

  • zig fmt मौजूदा फ़ाइल में पहले से मौजूद syntax shape को देखकर उसी syntax को कई तरीकों से व्यवस्थित कर सकता है, इसलिए इसे एक steerable formatter की तरह इस्तेमाल किया जा सकता है
  • function call में trailing comma की मौजूदगी layout बदल देती है
    f(1, 2,
          3);
    
    // -> zig fmt ->
    
        f(1, 2, 3);
    
    f(1, 2,
          3,);
    
    // -> zig fmt ->
    
        f(
            1,
            2,
            3,
        );
    
  • व्यावहारिक उपयोग में पहले मनचाहा code layout तय किया जाता है, फिर कुछ , जोड़े जाते हैं, और उसके बाद format shortcut दबाया जाता है ताकि zig fmt बाकी काम संभाल ले
  • formatter से layout का अनुमान लगवाने के बजाय, यह तरीका बेहतर बैठ सकता है कि उपयोगकर्ता खुद महत्वपूर्ण choices छोड़कर जाए
  • अच्छी formatting का 90% तार्किक blocks के बीच खाली लाइनों और उपयुक्त intermediate variables चुनने पर निर्भर करता है, इसलिए निष्कर्ष यह है कि ऐसी choices को हटाने के बजाय उनका उपयोग करना बेहतर है

arrays के column-aligned layouts

  • arrays में केवल trailing comma के कारण हर item अलग लाइन में नहीं जाता, बल्कि zig fmt पहले line break की स्थिति को भी ध्यान में रखता है
    .{ 1, 2, 3,
          4, 5, 6, 7, 8, 9, 10, 11,  };
    
  • अगर पहला line break तीसरे item के बाद हो, तो परिणाम भी 3-3 items के हिसाब से align होता है
    .{
            1,  2,  3,
            4,  5,  6,
            7,  8,  9,
            10, 11,
        };
    
  • ++ array concatenation का सावधानी से उपयोग करने पर हर लाइन में items की संख्या अलग रखी जा सकती है
  • subprocess को --key और value pairs भेजते समय fixed argument array और option-pair array को जोड़कर उन्हें नीचे की तरह align किया जा सकता है
    try run(&(.{ "aws", "s3", "sync", path, url } ++ .{
        "--include",            "*.html",
        "--include",            "*.xml",
        "--metadata-directive", "REPLACE",
        "--cache-control",      "max-age=0",
    }));
    

1 टिप्पणियां

 
GN⁺ 1 시간 전
Lobste.rs की राय
  • मुझे याद है कि gofmt में भी इसी तरह का formatting guidance behavior था, और ऐसे formatter मुझे rustfmt से ज़्यादा पसंद हैं
    फिर भी, मेरा मानना है कि formatter बिल्कुल न होने से किसी भी तरह का formatting automation होना बेहतर है

    • “formatter न होने से कुछ भी होना बेहतर है” — यह बात यूँ ही नज़रअंदाज़ करना मुश्किल है
      auto-formatter साधारणपन को लागू करते हैं, formatting में कमज़ोर लोगों को ऊपर उठाते हैं, लेकिन जो लोग इसे अच्छे से करते हैं उन्हें भी नीचे खींच लेते हैं
      collaboration में, अगर दूसरे लोग ऐसा चाहते हों या उनकी निजी formatting discipline पर भरोसा करना मुश्किल हो, तो मैं इसका इस्तेमाल करूँगा, लेकिन अकेले काम करते समय कभी नहीं
      मेरी अपनी पसंद है और formatter की भी अपनी पसंद है, और दोनों में समझौता नामुमकिन है
      फिर भी, इस लेख में जो दिखाया गया है वह अपने-आप में प्रभावशाली है
      उस वाक्य ने Fiddler on the Roof की matchmaker Yente की यह पंक्ति याद दिला दी: “बुरा पति भी—भगवान बचाए—पति न होने से बेहतर है!”
    • जितना मुझे याद है, Elm formatter भी इसी तरह काम करता था, और original formatting को नज़रअंदाज़ करने वाले formatter की तुलना में वह काफ़ी बेहतर लगा था
    • कुछ C++ projects में हम clang-format इस्तेमाल करते हैं, और वह भयानक है
      versions के बीच इसकी stability इतनी कम है कि clang-format upgrade करने पर ऐसा formatting commit बन जाता है जो code की लगभग हर line को छू देता है
      सच कहूँ तो यक़ीन नहीं कि यह formatter न होने से बेहतर है
    • पहले मैं लंबे समय तक सोचता था कि “कोई भी formatter, formatter न होने से बेहतर है”, लेकिन हाल में मेरी सोच पूरी तरह बदल गई है
      auto-formatter मुख्य रूप से pull request में होने वाली bike-shedding जैसी मानवीय समस्या को हल करते हैं
      लेकिन अब जब हम agentic development की ओर बढ़ रहे हैं, वह समस्या धीरे-धीरे कम महत्वपूर्ण होती जा रही है
      अभी कई projects में मशीनें ज़्यादातर काम कर रही हैं, और ऐसे में लगता है कि formatter न चलाना ही बेहतर हो सकता है
  • Python में command-line arguments बनाते समय मुझे tuple को list में splat करने का तरीका पसंद है, इसलिए लेख के आख़िरी example को मैं शायद ऐसे लिखूँगा

    [  
      "aws",  
      "s3",  
      "sync",  
      path,  
      url,  
            *("--include", "*.html"),  
      *("--include", "*.xml"),  
      *("--metadata-directive", "REPLACE"),  
      *("--cache-control", "max-age=0"),  
    ]  
    
  • पिछली बार जब मैंने देखा था, zig fmt में 80-column limit को 100-column limit की जगह इस्तेमाल करने का कोई तरीका नहीं था — क्या अभी भी ऐसा ही है?
    अगर रोज़ कई घंटे काम करना हो, तो आँखों पर कम ज़ोर पड़े इसलिए मैं terminal font size बड़ा रखता हूँ, और 80 columns बनाम 100 columns का फ़र्क यह तय करता है कि vim के दो splits और nerd tree को साथ-साथ रखा जा सकता है या नहीं

    • zig fmt में कोई column limit नहीं है
  • एक ऐसे व्यक्ति के रूप में जिसने ऐसी टीम में rigid formatter लागू किया था जहाँ पहले formatter था ही नहीं, मुझे कभी-कभी manual formatting को प्रभावित कर पाने की क्षमता की कमी महसूस होती है
    उस नज़रिए से Zig का flexible होना वाकई बहुत बढ़िया है

  • शानदार!
    क्या इस तरह का कोई TS/JS formatter है?
    मेरा एक project है जो maplibre-gl इस्तेमाल करता है, और style spec expressions कभी-कभी इतने ज़्यादा format हो जाते हैं कि कुछ दिखाई ही नहीं देता
    फ़िलहाल मैंने formatter का इस्तेमाल बंद कर दिया है, लेकिन debug करने, copy-paste करने और comments लगाने के दौरान code गंदा होता जा रहा है
    शायद Zig formatter को दूसरी भाषाओं के लिए भी formatting करने लायक बनाया जा सके :)

    • Prettier में भी कुछ ऐसा है, लेकिन विशेष रूप से यह object literals तक सीमित है, और इसमें सिर्फ़ “सब कुछ एक line में” या “हर element अलग line में” में से चुन सकते हैं
      उदाहरण के लिए, formatter को यह बताने का कोई तरीका नहीं है कि हर line में चार elements रखे
      और अगर object literal बहुत लंबा हो जाए, तो input text जैसा भी हो, Prettier आख़िरकार उसे “हर element अलग line में” वाले रूप में बदल देता है
  • हल्के किस्म के formatter, यानी लगभग सिर्फ line breaks करने वाले formatter, ने मुझे निराश किया है, इसलिए ज़्यादा सख़्त उदाहरणों के भीतर ऐसी flexibility का विचार ईर्ष्याजनक भी लगता है और अच्छा भी :p
    हाल ही में fedi पर proportional font में Lisp लिखने और format करने से जुड़े सवाल का जवाब देते हुए, मैंने meaningful whitespace इस्तेमाल करने वाले s-expression variants — wisp, Readable/Sweet expressions, और SRFI 119 व 110 — का ज़िक्र किया था
    मैंने यह भी जोड़ा कि यह syntax family optional infix notation extensions का उपयोग करके line breaks पर कुछ नियंत्रण वापस देती है

  • design दिलचस्प है, लेकिन मुझे यक़ीन नहीं कि यह मुझे पसंद है
    अपने formatter में मैं इसे अलग तरह से संभालता हूँ: formatter trailing comma को नज़रअंदाज़ करके formatting तय करता है, फिर अगर चीज़ कई lines में टूटती है तो हमेशा trailing comma जोड़ देता है, और अगर एक line में रहती है तो trailing comma हमेशा हटा देता है
    इसलिए “guidance” तो नहीं हो पाता, लेकिन f(1, 2, 3) trailing comma हो या न हो, या tokens के बीच spaces की मात्रा और प्रकार कुछ भी हो, हमेशा एक जैसा format होता है
    कुछ हद तक guidance की ज़रूरत होती है
    उदाहरण के लिए, अगर कोई लंबा list literal [<expr1>, <expr2>, ..., <expr100>] हो, तो ज़्यादातर formatter हर expression को अलग line में रखेंगे, लेकिन हो सकता है आप चाहें कि एक line में जितना हो सके उतना भरा जाए
    इसे trailing comma से तय करना मुझे अजीब लगता है, और आम तौर पर विकल्प 2 नहीं बल्कि N हो सकते हैं
    ऐसे उद्देश्य के लिए attributes ज़्यादा उपयुक्त लगते हैं
    उदाहरण के लिए, शायद यह पहले से हो भी, लेकिन किसी statement के आगे #[rustfmt::list_layout(flow)] जैसा कुछ लगाकर उस statement के भीतर list literals की formatting को प्रभावित किया जा सकता है
    बहुत ज़्यादा guidance देने से formatter के उद्देश्य को नुकसान पहुँचता है, क्योंकि उसका मक़सद पूरे ecosystem में code formatting को एकसमान बनाना और code review को आसान करना है, इसलिए यह सिर्फ़ सीमित मामलों में होना चाहिए
    लंबे list literals मुझे सच में ऐसा ही एक ज़रूरी मामला लगते हैं
    मेरे project में भी एक उदाहरण है जहाँ formatting test expectations की review में मदद करती है, यहाँ वैसा ही मामला है
    Dart formatter में एक और “guidance” behavior याद आता है: लंबे list literals में comment lines जोड़कर lines को group किया जा सकता है
    उदाहरण के लिए, अगर [1, 2, 3, ..., 1000] हो तो वह हर element को अलग line में रखेगा, लेकिन आप हाथ से इसे इस तरह group कर सकते हैं

    [1, 2, 3, 4, 5,  //  
     6, 7, 8, 9, 10, //  
     ...]  
    

    पता नहीं यह सुविधा जानबूझकर डाली गई थी या comment handling का एक side effect है

    • वही तो ठीक-ठीक rustfmt का behavior है, और यही बात मुझे पागल कर देती है
      कभी-कभी line length limit पार होने देने पर भी function call को न तोड़ना ज़्यादा readable होता है, और अच्छा होता अगर मैं उस पर अपना निर्णय लागू कर पाता
      एक उदाहरण जो तुरंत दिमाग में आता है, वह OpenGL है
      आम तौर पर आप एक ही resource को modify या use कर रहे होते हैं, और जैसे texture initialization में gl.* calls की लंबी श्रृंखला बन जाती है, लेकिन rustfmt किसी संवेदनशील समझ के बिना सिर्फ़ “line बहुत लंबी है, तोड़नी पड़ेगी” जैसी रोबोटिक प्राथमिकता से उसे तोड़ देता है
      यह example behavior दिखाने के लिए कृत्रिम है, और असली rustfmt behavior से बिल्कुल एक जैसा नहीं है
      lines भी इतनी लंबी नहीं हैं
      मैं अभी फ़ोन पर लिख रहा हूँ, इसलिए 100% सटीक example बनाने के साधन नहीं हैं
      gl.bind_texture(gl::TEXTURE_2D, tex);  
      gl.tex_parameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST);  
      gl.tex_parameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST);
      
      // -->
      
      gl.bind_texture(gl::TEXTURE_2D, tex);  
      gl.tex_parameteri(  
          gl::TEXTURE_2D,  
          gl::TEXTURE_MIN_FILTER,  
          gl::NEAREST,  
      );  
      gl.tex_parameteri(  
          gl::TEXTURE_2D,  
          gl::TEXTURE_MAG_FILTER,  
          gl::NEAREST,  
      );  
      
      इस तरह लगातार आने वाली gl.tex_parameteri calls को कई lines में तोड़ दिया जाता है, जबकि वास्तव में हर call को एक ही line में पूरी तरह फैलाकर रखना बेहतर है
      क्योंकि जब columns align होते हैं, तो दोनों lines के बीच का अंतर काफ़ी आसानी से दिख जाता है
      टूटा हुआ version visual proximity खो देता है और पढ़ने में मुश्किल हो जाता है
      आप दो lines की तुलना आँखों से आसानी से नहीं कर पाते
      एक और हास्यास्पद बात यह है कि जब formatter किसी चीज़ को character limit के अंदर fit नहीं कर पाता, तो वह पूरी तरह fail हो जाता है
      compiler code लिखते समय string literals में diagnostic messages बनाते हुए यह अक्सर होता है, क्योंकि message काफ़ी लंबे हो सकते हैं
      rustfmt समझ नहीं पाता कि इसे कैसे तोड़े, इसलिए हार मानकर पूरे statement को format ही नहीं करता
      आम तौर पर मामला कुछ ऐसा होता है
      match something {  
          // ... match arms above this one ...  
          _ => emit_diagnostic(&mut state, "This is a very long message to try and illustrate the problem. Help: please consult a doctor.")  
      }  
      
      यहाँ सिर्फ़ इसलिए कि emit_diagnostic call एक expression है, वह पूरे match statement की formatting छोड़ देता है — यह बस बेवकूफ़ी है
      अगर वह मेरे code को ज़बरदस्ती 100 columns के अंदर ठूँसने की कोशिश न करता, तो यह सब टल सकता था
  • आख़िर में, उस comment को देखकर मेरे जैसे जिन लोगों को यह खोजकर देखना पड़ा, उनके लिए: ++ array concatenation operator है
    इसलिए arrays को दो हिस्सों में बाँटकर उन्हें अलग-अलग तरह से format किया जा सकता है